]>
Commit | Line | Data |
---|---|---|
dcfacbbf | 1 | /* |
a28d06f3 | 2 | * Copyright 2020-2021 The OpenSSL Project Authors. All Rights Reserved. |
dcfacbbf RL |
3 | * |
4 | * Licensed under the Apache License 2.0 (the "License"). You may not use | |
5 | * this file except in compliance with the License. You can obtain a copy | |
6 | * in the file LICENSE in the source distribution or at | |
7 | * https://www.openssl.org/source/license.html | |
8 | */ | |
9 | ||
10 | /* | |
11 | * RSA low level APIs are deprecated for public use, but still ok for | |
12 | * internal use. | |
13 | */ | |
14 | #include "internal/deprecated.h" | |
15 | ||
436623f8 RL |
16 | #include <string.h> |
17 | ||
dcfacbbf RL |
18 | #include <openssl/core_dispatch.h> |
19 | #include <openssl/core_names.h> | |
70793dbb | 20 | #include <openssl/core_object.h> |
dcfacbbf | 21 | #include <openssl/crypto.h> |
436623f8 | 22 | #include <openssl/err.h> |
dcfacbbf RL |
23 | #include <openssl/params.h> |
24 | #include <openssl/pem.h> | |
2741128e | 25 | #include <openssl/proverr.h> |
ecadfdad | 26 | #include "internal/nelem.h" |
dcfacbbf | 27 | #include "prov/bio.h" |
71b35e19 | 28 | #include "prov/implementations.h" |
8ae40cf5 RL |
29 | #include "endecoder_local.h" |
30 | ||
31 | static int read_pem(PROV_CTX *provctx, OSSL_CORE_BIO *cin, | |
32 | char **pem_name, char **pem_header, | |
33 | unsigned char **data, long *len) | |
34 | { | |
9500c823 | 35 | BIO *in = ossl_bio_new_from_core_bio(provctx, cin); |
8ae40cf5 RL |
36 | int ok = (PEM_read_bio(in, pem_name, pem_header, data, len) > 0); |
37 | ||
38 | BIO_free(in); | |
39 | return ok; | |
40 | } | |
dcfacbbf | 41 | |
ece9304c RL |
42 | static OSSL_FUNC_decoder_newctx_fn pem2der_newctx; |
43 | static OSSL_FUNC_decoder_freectx_fn pem2der_freectx; | |
ece9304c | 44 | static OSSL_FUNC_decoder_decode_fn pem2der_decode; |
dcfacbbf | 45 | |
436623f8 | 46 | /* |
ece9304c | 47 | * Context used for PEM to DER decoding. |
436623f8 RL |
48 | */ |
49 | struct pem2der_ctx_st { | |
50 | PROV_CTX *provctx; | |
436623f8 RL |
51 | }; |
52 | ||
dcfacbbf RL |
53 | static void *pem2der_newctx(void *provctx) |
54 | { | |
436623f8 RL |
55 | struct pem2der_ctx_st *ctx = OPENSSL_zalloc(sizeof(*ctx)); |
56 | ||
57 | if (ctx != NULL) | |
58 | ctx->provctx = provctx; | |
59 | return ctx; | |
dcfacbbf RL |
60 | } |
61 | ||
62 | static void pem2der_freectx(void *vctx) | |
63 | { | |
436623f8 RL |
64 | struct pem2der_ctx_st *ctx = vctx; |
65 | ||
436623f8 | 66 | OPENSSL_free(ctx); |
dcfacbbf RL |
67 | } |
68 | ||
436623f8 | 69 | /* pem_password_cb compatible function */ |
4701f0a9 RL |
70 | struct pem2der_pass_data_st { |
71 | OSSL_PASSPHRASE_CALLBACK *cb; | |
72 | void *cbarg; | |
73 | }; | |
74 | ||
436623f8 RL |
75 | static int pem2der_pass_helper(char *buf, int num, int w, void *data) |
76 | { | |
4701f0a9 | 77 | struct pem2der_pass_data_st *pass_data = data; |
436623f8 RL |
78 | size_t plen; |
79 | ||
4701f0a9 RL |
80 | if (pass_data == NULL |
81 | || pass_data->cb == NULL | |
82 | || !pass_data->cb(buf, num, &plen, NULL, pass_data->cbarg)) | |
436623f8 | 83 | return -1; |
4701f0a9 | 84 | return (int)plen; |
436623f8 RL |
85 | } |
86 | ||
2c090c1d RL |
87 | /* |
88 | * The selection parameter in pem2der_decode() is not used by this function | |
89 | * because it's not relevant just to decode PEM to DER. | |
90 | */ | |
91 | static int pem2der_decode(void *vctx, OSSL_CORE_BIO *cin, int selection, | |
ece9304c RL |
92 | OSSL_CALLBACK *data_cb, void *data_cbarg, |
93 | OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) | |
dcfacbbf | 94 | { |
70793dbb MC |
95 | /* Strings to peel off the pem name */ |
96 | static struct peelablee_pem_name_endings_st { | |
97 | const char *ending; | |
98 | const char *data_structure; | |
99 | } peelable_pem_name_endings[] = { | |
ecadfdad RL |
100 | /* |
101 | * These entries should be in longest to shortest order to avoid | |
102 | * mixups. | |
103 | */ | |
70793dbb MC |
104 | { "ENCRYPTED PRIVATE KEY", "pkcs8" }, |
105 | { "PRIVATE KEY", "pkcs8" }, | |
106 | { "PUBLIC KEY", "SubjectPublicKeyInfo" }, | |
107 | { "PARAMETERS", NULL } | |
ecadfdad RL |
108 | |
109 | /* | |
110 | * Libcrypto currently only supports decoding keys with provider side | |
70793dbb | 111 | * decoders, so we don't try to peel any other PEM name. That's an |
ecadfdad RL |
112 | * exercise for when libcrypto starts to treat other types of objects |
113 | * via providers. | |
114 | */ | |
115 | }; | |
436623f8 | 116 | struct pem2der_ctx_st *ctx = vctx; |
dcfacbbf | 117 | char *pem_name = NULL, *pem_header = NULL; |
ecadfdad | 118 | size_t pem_name_len, i; |
dcfacbbf RL |
119 | unsigned char *der = NULL; |
120 | long der_len = 0; | |
121 | int ok = 0; | |
70793dbb MC |
122 | int objtype = OSSL_OBJECT_UNKNOWN; |
123 | const char *data_structure = NULL; | |
dcfacbbf | 124 | |
9cc97ddf RL |
125 | ok = read_pem(ctx->provctx, cin, &pem_name, &pem_header, |
126 | &der, &der_len) > 0; | |
127 | /* We return "empty handed". This is not an error. */ | |
128 | if (!ok) | |
129 | return 1; | |
dcfacbbf | 130 | |
dcfacbbf RL |
131 | /* |
132 | * 10 is the number of characters in "Proc-Type:", which | |
133 | * PEM_get_EVP_CIPHER_INFO() requires to be present. | |
134 | * If the PEM header has less characters than that, it's | |
135 | * not worth spending cycles on it. | |
136 | */ | |
436623f8 | 137 | if (strlen(pem_header) > 10) { |
dcfacbbf | 138 | EVP_CIPHER_INFO cipher; |
4701f0a9 | 139 | struct pem2der_pass_data_st pass_data; |
dcfacbbf | 140 | |
9cc97ddf | 141 | ok = 0; /* Assume that we fail */ |
4701f0a9 RL |
142 | pass_data.cb = pw_cb; |
143 | pass_data.cbarg = pw_cbarg; | |
436623f8 | 144 | if (!PEM_get_EVP_CIPHER_INFO(pem_header, &cipher) |
4701f0a9 RL |
145 | || !PEM_do_header(&cipher, der, &der_len, |
146 | pem2der_pass_helper, &pass_data)) | |
dcfacbbf RL |
147 | goto end; |
148 | } | |
dcfacbbf | 149 | |
9cc97ddf RL |
150 | /* |
151 | * Indicated that we successfully decoded something, or not at all. | |
152 | * Ending up "empty handed" is not an error. | |
153 | */ | |
154 | ok = 1; | |
155 | ||
ecadfdad RL |
156 | /* |
157 | * Peal off certain strings from the end of |pem_name|, as they serve | |
158 | * no further purpose. | |
159 | */ | |
160 | for (i = 0, pem_name_len = strlen(pem_name); | |
70793dbb | 161 | i < OSSL_NELEM(peelable_pem_name_endings); |
ecadfdad | 162 | i++) { |
70793dbb | 163 | size_t peel_len = strlen(peelable_pem_name_endings[i].ending); |
ecadfdad RL |
164 | size_t pem_name_offset; |
165 | ||
70793dbb MC |
166 | if (peel_len <= pem_name_len) { |
167 | pem_name_offset = pem_name_len - peel_len; | |
ecadfdad | 168 | if (strcmp(pem_name + pem_name_offset, |
70793dbb | 169 | peelable_pem_name_endings[i].ending) == 0) { |
ecadfdad RL |
170 | |
171 | do { | |
172 | pem_name[pem_name_offset] = '\0'; | |
173 | } while (pem_name_offset > 0 | |
174 | && pem_name[--pem_name_offset] == ' '); | |
175 | ||
176 | if (pem_name[0] == '\0') { | |
177 | OPENSSL_free(pem_name); | |
178 | pem_name = NULL; | |
179 | } | |
70793dbb MC |
180 | /* All of these peelable endings are for EVP_PKEYs */ |
181 | objtype = OSSL_OBJECT_PKEY; | |
182 | if (pem_name == NULL) { | |
183 | data_structure = peelable_pem_name_endings[i].data_structure; | |
184 | if (data_structure == NULL) | |
185 | goto end; | |
186 | } else { | |
187 | /* | |
188 | * If there is an algorithm name prefix then it is a | |
189 | * type-specific data structure | |
190 | */ | |
191 | data_structure = "type-specific"; | |
192 | } | |
ecadfdad RL |
193 | break; |
194 | } | |
195 | } | |
196 | } | |
197 | ||
70793dbb MC |
198 | /* If we don't know the object type yet check if it's one we know about */ |
199 | if (objtype == OSSL_OBJECT_UNKNOWN) { | |
200 | if (strcmp(pem_name, PEM_STRING_X509) == 0 | |
201 | || strcmp(pem_name, PEM_STRING_X509_TRUSTED) == 0 | |
202 | || strcmp(pem_name, PEM_STRING_X509_OLD) == 0) | |
203 | objtype = OSSL_OBJECT_CERT; | |
204 | else if (strcmp(pem_name, PEM_STRING_X509_CRL) == 0) | |
205 | objtype = OSSL_OBJECT_CRL; | |
206 | } | |
207 | ||
dcfacbbf | 208 | { |
70793dbb | 209 | OSSL_PARAM params[5], *p = params; |
dcfacbbf | 210 | |
ecadfdad RL |
211 | if (pem_name != NULL) |
212 | *p++ = | |
213 | OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_TYPE, | |
214 | pem_name, 0); | |
70793dbb MC |
215 | |
216 | /* We expect this to be read only so casting away the const is ok */ | |
217 | if (data_structure != NULL) | |
218 | *p++ = | |
219 | OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_STRUCTURE, | |
220 | (char *)data_structure, 0); | |
ecadfdad | 221 | *p++ = |
14c8a3d1 | 222 | OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_DATA, |
dcfacbbf | 223 | der, der_len); |
70793dbb MC |
224 | *p++ = |
225 | OSSL_PARAM_construct_int(OSSL_OBJECT_PARAM_TYPE, &objtype); | |
226 | ||
ecadfdad | 227 | *p = OSSL_PARAM_construct_end(); |
dcfacbbf RL |
228 | |
229 | ok = data_cb(params, data_cbarg); | |
230 | } | |
231 | ||
436623f8 | 232 | end: |
dcfacbbf RL |
233 | OPENSSL_free(pem_name); |
234 | OPENSSL_free(pem_header); | |
235 | OPENSSL_free(der); | |
236 | return ok; | |
237 | } | |
238 | ||
1be63951 | 239 | const OSSL_DISPATCH ossl_pem_to_der_decoder_functions[] = { |
ece9304c RL |
240 | { OSSL_FUNC_DECODER_NEWCTX, (void (*)(void))pem2der_newctx }, |
241 | { OSSL_FUNC_DECODER_FREECTX, (void (*)(void))pem2der_freectx }, | |
ece9304c | 242 | { OSSL_FUNC_DECODER_DECODE, (void (*)(void))pem2der_decode }, |
dcfacbbf RL |
243 | { 0, NULL } |
244 | }; |