]>
Commit | Line | Data |
---|---|---|
fde2257f VD |
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 | } |