Extend mkcert.sh to support nameConstraints generation and more complex
[openssl.git] / test / x509aux.c
1 /*
2  * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the OpenSSL licenses, (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  * https://www.openssl.org/source/license.html
8  * or in the file LICENSE in the source distribution.
9  */
10
11 #include <stdio.h>
12 #include <string.h>
13 #include <errno.h>
14
15 #include <openssl/x509.h>
16 #include <openssl/pem.h>
17 #include <openssl/conf.h>
18 #include <openssl/err.h>
19
20 #include "../e_os.h"
21
22 static const char *progname;
23
24 static void test_usage(void)
25 {
26     fprintf(stderr, "usage: %s certfile\n", progname);
27 }
28
29 static void print_errors(void)
30 {
31     unsigned long err;
32     char buffer[1024];
33     const char *file;
34     const char *data;
35     int line;
36     int flags;
37
38     while ((err = ERR_get_error_line_data(&file, &line, &data, &flags)) != 0) {
39         ERR_error_string_n(err, buffer, sizeof(buffer));
40         if (flags & ERR_TXT_STRING)
41             fprintf(stderr, "Error: %s:%s:%d:%s\n", buffer, file, line, data);
42         else
43             fprintf(stderr, "Error: %s:%s:%d\n", buffer, file, line);
44     }
45 }
46
47 static int test_certs(BIO *fp)
48 {
49     int count;
50     char *name = 0;
51     char *header = 0;
52     unsigned char *data = 0;
53     long len;
54     typedef X509 *(*d2i_X509_t)(X509 **, const unsigned char **, long);
55     typedef int (*i2d_X509_t)(X509 *, unsigned char **);
56     int err = 0;
57
58     for (count = 0;
59          !err && PEM_read_bio(fp, &name, &header, &data, &len);
60          ++count) {
61         int trusted = strcmp(name, PEM_STRING_X509_TRUSTED) == 0;
62         d2i_X509_t d2i = trusted ? d2i_X509_AUX : d2i_X509;
63         i2d_X509_t i2d = trusted ? i2d_X509_AUX : i2d_X509;
64         X509 *cert = NULL;
65         const unsigned char *p = data;
66         unsigned char *buf = NULL;
67         unsigned char *bufp;
68         long enclen;
69
70         if (!trusted
71             && strcmp(name, PEM_STRING_X509) != 0
72             && strcmp(name, PEM_STRING_X509_OLD) != 0) {
73             fprintf(stderr, "unexpected PEM object: %s\n", name);
74             err = 1;
75             goto next;
76         }
77         cert = d2i(NULL, &p, len);
78
79         if (cert == NULL || (p - data) != len) {
80             fprintf(stderr, "error parsing input %s\n", name);
81             err = 1;
82             goto next;
83         }
84
85         /* Test traditional 2-pass encoding into caller allocated buffer */
86         enclen = i2d(cert, NULL);
87         if (len != enclen) {
88             fprintf(stderr, "encoded length %ld of %s != input length %ld\n",
89                     enclen, name, len);
90             err = 1;
91             goto next;
92         }
93         if ((buf = bufp = OPENSSL_malloc(len)) == NULL) {
94             perror("malloc");
95             err = 1;
96             goto next;
97         }
98         enclen = i2d(cert, &bufp);
99         if (len != enclen) {
100             fprintf(stderr, "encoded length %ld of %s != input length %ld\n",
101                     enclen, name, len);
102             err = 1;
103             goto next;
104         }
105         enclen = (long) (bufp - buf);
106         if (enclen != len) {
107             fprintf(stderr, "unexpected buffer position after encoding %s\n",
108                     name);
109             err = 1;
110             goto next;
111         }
112         if (memcmp(buf, data, len) != 0) {
113             fprintf(stderr, "encoded content of %s does not match input\n",
114                     name);
115             err = 1;
116             goto next;
117         }
118         OPENSSL_free(buf);
119         buf = NULL;
120
121         /* Test 1-pass encoding into library allocated buffer */
122         enclen = i2d(cert, &buf);
123         if (len != enclen) {
124             fprintf(stderr, "encoded length %ld of %s != input length %ld\n",
125                     enclen, name, len);
126             err = 1;
127             goto next;
128         }
129         if (memcmp(buf, data, len) != 0) {
130             fprintf(stderr, "encoded content of %s does not match input\n",
131                     name);
132             err = 1;
133             goto next;
134         }
135
136         if (trusted) {
137             /* Encode just the cert and compare with initial encoding */
138             OPENSSL_free(buf);
139             buf = NULL;
140
141             /* Test 1-pass encoding into library allocated buffer */
142             enclen = i2d(cert, &buf);
143             if (enclen > len) {
144                 fprintf(stderr, "encoded length %ld of %s > input length %ld\n",
145                         enclen, name, len);
146                 err = 1;
147                 goto next;
148             }
149             if (memcmp(buf, data, enclen) != 0) {
150                 fprintf(stderr, "encoded cert content does not match input\n");
151                 err = 1;
152                 goto next;
153             }
154         }
155
156         /*
157          * If any of these were null, PEM_read() would have failed.
158          */
159     next:
160         X509_free(cert);
161         OPENSSL_free(buf);
162         OPENSSL_free(name);
163         OPENSSL_free(header);
164         OPENSSL_free(data);
165     }
166
167     if (ERR_GET_REASON(ERR_peek_last_error()) == PEM_R_NO_START_LINE) {
168         /* Reached end of PEM file */
169         if (count > 0) {
170             ERR_clear_error();
171             return 1;
172         }
173     }
174
175     /* Some other PEM read error */
176     print_errors();
177     return 0;
178 }
179
180 int main(int argc, char *argv[])
181 {
182     BIO *bio_err;
183     const char *certfile;
184     const char *p;
185     int ret = 1;
186
187     progname = argv[0];
188     if (argc < 2) {
189         test_usage();
190         EXIT(ret);
191     }
192
193     bio_err = BIO_new_fp(stderr, BIO_NOCLOSE | BIO_FP_TEXT);
194
195     p = getenv("OPENSSL_DEBUG_MEMORY");
196     if (p != NULL && strcmp(p, "on") == 0)
197         CRYPTO_set_mem_debug(1);
198     CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
199
200     while ((certfile = *++argv) != NULL) {
201         BIO *f = BIO_new_file(certfile, "r");
202         int ok;
203
204         if (f == NULL) {
205             fprintf(stderr, "%s: Error opening cert file: '%s': %s\n",
206                     progname, certfile, strerror(errno));
207             EXIT(ret);
208         }
209         ret = !(ok = test_certs(f));
210         BIO_free(f);
211
212         if (!ok) {
213             printf("%s ERROR\n", certfile);
214             ret = 1;
215             break;
216         }
217         printf("%s OK\n", certfile);
218     }
219
220 #ifndef OPENSSL_NO_CRYPTO_MDEBUG
221     if (CRYPTO_mem_leaks(bio_err) <= 0)
222         ret = 1;
223 #endif
224     BIO_free(bio_err);
225     EXIT(ret);
226 }