/src/boringssl/crypto/pem/pem_info.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) |
2 | | * All rights reserved. |
3 | | * |
4 | | * This package is an SSL implementation written |
5 | | * by Eric Young (eay@cryptsoft.com). |
6 | | * The implementation was written so as to conform with Netscapes SSL. |
7 | | * |
8 | | * This library is free for commercial and non-commercial use as long as |
9 | | * the following conditions are aheared to. The following conditions |
10 | | * apply to all code found in this distribution, be it the RC4, RSA, |
11 | | * lhash, DES, etc., code; not just the SSL code. The SSL documentation |
12 | | * included with this distribution is covered by the same copyright terms |
13 | | * except that the holder is Tim Hudson (tjh@cryptsoft.com). |
14 | | * |
15 | | * Copyright remains Eric Young's, and as such any Copyright notices in |
16 | | * the code are not to be removed. |
17 | | * If this package is used in a product, Eric Young should be given attribution |
18 | | * as the author of the parts of the library used. |
19 | | * This can be in the form of a textual message at program startup or |
20 | | * in documentation (online or textual) provided with the package. |
21 | | * |
22 | | * Redistribution and use in source and binary forms, with or without |
23 | | * modification, are permitted provided that the following conditions |
24 | | * are met: |
25 | | * 1. Redistributions of source code must retain the copyright |
26 | | * notice, this list of conditions and the following disclaimer. |
27 | | * 2. Redistributions in binary form must reproduce the above copyright |
28 | | * notice, this list of conditions and the following disclaimer in the |
29 | | * documentation and/or other materials provided with the distribution. |
30 | | * 3. All advertising materials mentioning features or use of this software |
31 | | * must display the following acknowledgement: |
32 | | * "This product includes cryptographic software written by |
33 | | * Eric Young (eay@cryptsoft.com)" |
34 | | * The word 'cryptographic' can be left out if the rouines from the library |
35 | | * being used are not cryptographic related :-). |
36 | | * 4. If you include any Windows specific code (or a derivative thereof) from |
37 | | * the apps directory (application code) you must include an acknowledgement: |
38 | | * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" |
39 | | * |
40 | | * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND |
41 | | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
42 | | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
43 | | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
44 | | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
45 | | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
46 | | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
47 | | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
48 | | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
49 | | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
50 | | * SUCH DAMAGE. |
51 | | * |
52 | | * The licence and distribution terms for any publically available version or |
53 | | * derivative of this code cannot be changed. i.e. this code cannot simply be |
54 | | * copied and put under another distribution licence |
55 | | * [including the GNU Public Licence.] |
56 | | */ |
57 | | |
58 | | #include <openssl/pem.h> |
59 | | |
60 | | #include <assert.h> |
61 | | #include <stdio.h> |
62 | | #include <string.h> |
63 | | |
64 | | #include <openssl/dsa.h> |
65 | | #include <openssl/err.h> |
66 | | #include <openssl/evp.h> |
67 | | #include <openssl/mem.h> |
68 | | #include <openssl/obj.h> |
69 | | #include <openssl/rsa.h> |
70 | | #include <openssl/x509.h> |
71 | | |
72 | | STACK_OF(X509_INFO) *PEM_X509_INFO_read(FILE *fp, STACK_OF(X509_INFO) *sk, |
73 | 0 | pem_password_cb *cb, void *u) { |
74 | 0 | BIO *b = BIO_new_fp(fp, BIO_NOCLOSE); |
75 | 0 | if (b == NULL) { |
76 | 0 | OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB); |
77 | 0 | return 0; |
78 | 0 | } |
79 | 0 | STACK_OF(X509_INFO) *ret = PEM_X509_INFO_read_bio(b, sk, cb, u); |
80 | 0 | BIO_free(b); |
81 | 0 | return ret; |
82 | 0 | } |
83 | | |
84 | | enum parse_result_t { |
85 | | parse_ok, |
86 | | parse_error, |
87 | | parse_new_entry, |
88 | | }; |
89 | | |
90 | | static enum parse_result_t parse_x509(X509_INFO *info, const uint8_t *data, |
91 | 0 | size_t len, int key_type) { |
92 | 0 | if (info->x509 != NULL) { |
93 | 0 | return parse_new_entry; |
94 | 0 | } |
95 | 0 | info->x509 = d2i_X509(NULL, &data, len); |
96 | 0 | return info->x509 != NULL ? parse_ok : parse_error; |
97 | 0 | } |
98 | | |
99 | | static enum parse_result_t parse_x509_aux(X509_INFO *info, const uint8_t *data, |
100 | 0 | size_t len, int key_type) { |
101 | 0 | if (info->x509 != NULL) { |
102 | 0 | return parse_new_entry; |
103 | 0 | } |
104 | 0 | info->x509 = d2i_X509_AUX(NULL, &data, len); |
105 | 0 | return info->x509 != NULL ? parse_ok : parse_error; |
106 | 0 | } |
107 | | |
108 | | static enum parse_result_t parse_crl(X509_INFO *info, const uint8_t *data, |
109 | 0 | size_t len, int key_type) { |
110 | 0 | if (info->crl != NULL) { |
111 | 0 | return parse_new_entry; |
112 | 0 | } |
113 | 0 | info->crl = d2i_X509_CRL(NULL, &data, len); |
114 | 0 | return info->crl != NULL ? parse_ok : parse_error; |
115 | 0 | } |
116 | | |
117 | | static enum parse_result_t parse_key(X509_INFO *info, const uint8_t *data, |
118 | 0 | size_t len, int key_type) { |
119 | 0 | if (info->x_pkey != NULL) { |
120 | 0 | return parse_new_entry; |
121 | 0 | } |
122 | 0 | info->x_pkey = X509_PKEY_new(); |
123 | 0 | if (info->x_pkey == NULL) { |
124 | 0 | return parse_error; |
125 | 0 | } |
126 | 0 | info->x_pkey->dec_pkey = d2i_PrivateKey(key_type, NULL, &data, len); |
127 | 0 | return info->x_pkey->dec_pkey != NULL ? parse_ok : parse_error; |
128 | 0 | } |
129 | | |
130 | | STACK_OF(X509_INFO) *PEM_X509_INFO_read_bio(BIO *bp, STACK_OF(X509_INFO) *sk, |
131 | 0 | pem_password_cb *cb, void *u) { |
132 | 0 | X509_INFO *info = NULL; |
133 | 0 | char *name = NULL, *header = NULL; |
134 | 0 | unsigned char *data = NULL; |
135 | 0 | long len; |
136 | 0 | int ok = 0; |
137 | 0 | STACK_OF(X509_INFO) *ret = NULL; |
138 | |
|
139 | 0 | if (sk == NULL) { |
140 | 0 | ret = sk_X509_INFO_new_null(); |
141 | 0 | if (ret == NULL) { |
142 | 0 | return NULL; |
143 | 0 | } |
144 | 0 | } else { |
145 | 0 | ret = sk; |
146 | 0 | } |
147 | 0 | size_t orig_num = sk_X509_INFO_num(ret); |
148 | |
|
149 | 0 | info = X509_INFO_new(); |
150 | 0 | if (info == NULL) { |
151 | 0 | goto err; |
152 | 0 | } |
153 | | |
154 | 0 | for (;;) { |
155 | 0 | if (!PEM_read_bio(bp, &name, &header, &data, &len)) { |
156 | 0 | uint32_t error = ERR_peek_last_error(); |
157 | 0 | if (ERR_GET_LIB(error) == ERR_LIB_PEM && |
158 | 0 | ERR_GET_REASON(error) == PEM_R_NO_START_LINE) { |
159 | 0 | ERR_clear_error(); |
160 | 0 | break; |
161 | 0 | } |
162 | 0 | goto err; |
163 | 0 | } |
164 | | |
165 | 0 | enum parse_result_t (*parse_function)(X509_INFO *, const uint8_t *, size_t, |
166 | 0 | int) = NULL; |
167 | 0 | int key_type = EVP_PKEY_NONE; |
168 | 0 | if (strcmp(name, PEM_STRING_X509) == 0 || |
169 | 0 | strcmp(name, PEM_STRING_X509_OLD) == 0) { |
170 | 0 | parse_function = parse_x509; |
171 | 0 | } else if (strcmp(name, PEM_STRING_X509_TRUSTED) == 0) { |
172 | 0 | parse_function = parse_x509_aux; |
173 | 0 | } else if (strcmp(name, PEM_STRING_X509_CRL) == 0) { |
174 | 0 | parse_function = parse_crl; |
175 | 0 | } else if (strcmp(name, PEM_STRING_RSA) == 0) { |
176 | 0 | parse_function = parse_key; |
177 | 0 | key_type = EVP_PKEY_RSA; |
178 | 0 | } else if (strcmp(name, PEM_STRING_DSA) == 0) { |
179 | 0 | parse_function = parse_key; |
180 | 0 | key_type = EVP_PKEY_DSA; |
181 | 0 | } else if (strcmp(name, PEM_STRING_ECPRIVATEKEY) == 0) { |
182 | 0 | parse_function = parse_key; |
183 | 0 | key_type = EVP_PKEY_EC; |
184 | 0 | } |
185 | | |
186 | | // If a private key has a header, assume it is encrypted. |
187 | 0 | if (key_type != EVP_PKEY_NONE && strlen(header) > 10) { |
188 | 0 | if (info->x_pkey != NULL) { |
189 | 0 | if (!sk_X509_INFO_push(ret, info)) { |
190 | 0 | goto err; |
191 | 0 | } |
192 | 0 | info = X509_INFO_new(); |
193 | 0 | if (info == NULL) { |
194 | 0 | goto err; |
195 | 0 | } |
196 | 0 | } |
197 | | // Historically, raw entries pushed an empty key. |
198 | 0 | info->x_pkey = X509_PKEY_new(); |
199 | 0 | if (info->x_pkey == NULL || |
200 | 0 | !PEM_get_EVP_CIPHER_INFO(header, &info->enc_cipher)) { |
201 | 0 | goto err; |
202 | 0 | } |
203 | 0 | info->enc_data = (char *)data; |
204 | 0 | info->enc_len = (int)len; |
205 | 0 | data = NULL; |
206 | 0 | } else if (parse_function != NULL) { |
207 | 0 | EVP_CIPHER_INFO cipher; |
208 | 0 | if (!PEM_get_EVP_CIPHER_INFO(header, &cipher) || |
209 | 0 | !PEM_do_header(&cipher, data, &len, cb, u)) { |
210 | 0 | goto err; |
211 | 0 | } |
212 | 0 | enum parse_result_t result = parse_function(info, data, len, key_type); |
213 | 0 | if (result == parse_new_entry) { |
214 | 0 | if (!sk_X509_INFO_push(ret, info)) { |
215 | 0 | goto err; |
216 | 0 | } |
217 | 0 | info = X509_INFO_new(); |
218 | 0 | if (info == NULL) { |
219 | 0 | goto err; |
220 | 0 | } |
221 | 0 | result = parse_function(info, data, len, key_type); |
222 | 0 | } |
223 | 0 | if (result != parse_ok) { |
224 | 0 | OPENSSL_PUT_ERROR(PEM, ERR_R_ASN1_LIB); |
225 | 0 | goto err; |
226 | 0 | } |
227 | 0 | } |
228 | 0 | OPENSSL_free(name); |
229 | 0 | OPENSSL_free(header); |
230 | 0 | OPENSSL_free(data); |
231 | 0 | name = NULL; |
232 | 0 | header = NULL; |
233 | 0 | data = NULL; |
234 | 0 | } |
235 | | |
236 | | // Push the last entry on the stack if not empty. |
237 | 0 | if (info->x509 != NULL || info->crl != NULL || info->x_pkey != NULL || |
238 | 0 | info->enc_data != NULL) { |
239 | 0 | if (!sk_X509_INFO_push(ret, info)) { |
240 | 0 | goto err; |
241 | 0 | } |
242 | 0 | info = NULL; |
243 | 0 | } |
244 | | |
245 | 0 | ok = 1; |
246 | |
|
247 | 0 | err: |
248 | 0 | X509_INFO_free(info); |
249 | 0 | if (!ok) { |
250 | 0 | while (sk_X509_INFO_num(ret) > orig_num) { |
251 | 0 | X509_INFO_free(sk_X509_INFO_pop(ret)); |
252 | 0 | } |
253 | 0 | if (ret != sk) { |
254 | 0 | sk_X509_INFO_free(ret); |
255 | 0 | } |
256 | 0 | ret = NULL; |
257 | 0 | } |
258 | |
|
259 | 0 | OPENSSL_free(name); |
260 | 0 | OPENSSL_free(header); |
261 | 0 | OPENSSL_free(data); |
262 | 0 | return ret; |
263 | 0 | } |