2 * Copyright 2020-2022 The OpenSSL Project Authors. All Rights Reserved.
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
11 * RSA low level APIs are deprecated for public use, but still ok for
14 #include "internal/deprecated.h"
18 #include <openssl/core_dispatch.h>
19 #include <openssl/core_names.h>
20 #include <openssl/core_object.h>
21 #include <openssl/crypto.h>
22 #include <openssl/err.h>
23 #include <openssl/params.h>
24 #include <openssl/pem.h>
25 #include <openssl/proverr.h>
26 #include "internal/nelem.h"
28 #include "prov/implementations.h"
29 #include "endecoder_local.h"
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
)
35 BIO
*in
= ossl_bio_new_from_core_bio(provctx
, cin
);
40 ok
= (PEM_read_bio(in
, pem_name
, pem_header
, data
, len
) > 0);
46 static OSSL_FUNC_decoder_newctx_fn pem2der_newctx
;
47 static OSSL_FUNC_decoder_freectx_fn pem2der_freectx
;
48 static OSSL_FUNC_decoder_decode_fn pem2der_decode
;
51 * Context used for PEM to DER decoding.
53 struct pem2der_ctx_st
{
57 static void *pem2der_newctx(void *provctx
)
59 struct pem2der_ctx_st
*ctx
= OPENSSL_zalloc(sizeof(*ctx
));
62 ctx
->provctx
= provctx
;
66 static void pem2der_freectx(void *vctx
)
68 struct pem2der_ctx_st
*ctx
= vctx
;
73 /* pem_password_cb compatible function */
74 struct pem2der_pass_data_st
{
75 OSSL_PASSPHRASE_CALLBACK
*cb
;
79 static int pem2der_pass_helper(char *buf
, int num
, int w
, void *data
)
81 struct pem2der_pass_data_st
*pass_data
= data
;
85 || pass_data
->cb
== NULL
86 || !pass_data
->cb(buf
, num
, &plen
, NULL
, pass_data
->cbarg
))
92 * The selection parameter in pem2der_decode() is not used by this function
93 * because it's not relevant just to decode PEM to DER.
95 static int pem2der_decode(void *vctx
, OSSL_CORE_BIO
*cin
, int selection
,
96 OSSL_CALLBACK
*data_cb
, void *data_cbarg
,
97 OSSL_PASSPHRASE_CALLBACK
*pw_cb
, void *pw_cbarg
)
100 * PEM names we recognise. Other PEM names should be recognised by
101 * other decoder implementations.
103 static struct pem_name_map_st
{
104 const char *pem_name
;
106 const char *data_type
;
107 const char *data_structure
;
109 /* PKCS#8 and SubjectPublicKeyInfo */
110 { PEM_STRING_PKCS8
, OSSL_OBJECT_PKEY
, NULL
, "EncryptedPrivateKeyInfo" },
111 { PEM_STRING_PKCS8INF
, OSSL_OBJECT_PKEY
, NULL
, "PrivateKeyInfo" },
112 { PEM_STRING_PUBLIC
, OSSL_OBJECT_PKEY
, NULL
, "SubjectPublicKeyInfo" },
114 /* Our set of type specific PEM types */
115 { PEM_STRING_DHPARAMS
, OSSL_OBJECT_PKEY
, "DH", "type-specific" },
116 { PEM_STRING_DHXPARAMS
, OSSL_OBJECT_PKEY
, "X9.42 DH", "type-specific" },
117 { PEM_STRING_DSA
, OSSL_OBJECT_PKEY
, "DSA", "type-specific" },
118 { PEM_STRING_DSA_PUBLIC
, OSSL_OBJECT_PKEY
, "DSA", "type-specific" },
119 { PEM_STRING_DSAPARAMS
, OSSL_OBJECT_PKEY
, "DSA", "type-specific" },
120 { PEM_STRING_ECPRIVATEKEY
, OSSL_OBJECT_PKEY
, "EC", "type-specific" },
121 { PEM_STRING_ECPARAMETERS
, OSSL_OBJECT_PKEY
, "EC", "type-specific" },
122 { PEM_STRING_RSA
, OSSL_OBJECT_PKEY
, "RSA", "type-specific" },
123 { PEM_STRING_RSA_PUBLIC
, OSSL_OBJECT_PKEY
, "RSA", "type-specific" },
126 * A few others that there is at least have an object type for, even
127 * though there is no provider interface to handle such objects, yet.
128 * However, this is beneficial for the OSSL_STORE result handler.
130 { PEM_STRING_X509
, OSSL_OBJECT_CERT
, NULL
, "Certificate" },
131 { PEM_STRING_X509_TRUSTED
, OSSL_OBJECT_CERT
, NULL
, "Certificate" },
132 { PEM_STRING_X509_OLD
, OSSL_OBJECT_CERT
, NULL
, "Certificate" },
133 { PEM_STRING_X509_CRL
, OSSL_OBJECT_CRL
, NULL
, "CertificateList" }
135 struct pem2der_ctx_st
*ctx
= vctx
;
136 char *pem_name
= NULL
, *pem_header
= NULL
;
138 unsigned char *der
= NULL
;
141 int objtype
= OSSL_OBJECT_UNKNOWN
;
143 ok
= read_pem(ctx
->provctx
, cin
, &pem_name
, &pem_header
,
145 /* We return "empty handed". This is not an error. */
150 * 10 is the number of characters in "Proc-Type:", which
151 * PEM_get_EVP_CIPHER_INFO() requires to be present.
152 * If the PEM header has less characters than that, it's
153 * not worth spending cycles on it.
155 if (strlen(pem_header
) > 10) {
156 EVP_CIPHER_INFO cipher
;
157 struct pem2der_pass_data_st pass_data
;
159 ok
= 0; /* Assume that we fail */
160 pass_data
.cb
= pw_cb
;
161 pass_data
.cbarg
= pw_cbarg
;
162 if (!PEM_get_EVP_CIPHER_INFO(pem_header
, &cipher
)
163 || !PEM_do_header(&cipher
, der
, &der_len
,
164 pem2der_pass_helper
, &pass_data
))
169 * Indicated that we successfully decoded something, or not at all.
170 * Ending up "empty handed" is not an error.
174 /* Have a look to see if we recognise anything */
175 for (i
= 0; i
< OSSL_NELEM(pem_name_map
); i
++)
176 if (strcmp(pem_name
, pem_name_map
[i
].pem_name
) == 0)
179 if (i
< OSSL_NELEM(pem_name_map
)) {
180 OSSL_PARAM params
[5], *p
= params
;
181 /* We expect these to be read only so casting away the const is ok */
182 char *data_type
= (char *)pem_name_map
[i
].data_type
;
183 char *data_structure
= (char *)pem_name_map
[i
].data_structure
;
185 objtype
= pem_name_map
[i
].object_type
;
186 if (data_type
!= NULL
)
188 OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_TYPE
,
191 /* We expect this to be read only so casting away the const is ok */
192 if (data_structure
!= NULL
)
194 OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_STRUCTURE
,
197 OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_DATA
,
200 OSSL_PARAM_construct_int(OSSL_OBJECT_PARAM_TYPE
, &objtype
);
202 *p
= OSSL_PARAM_construct_end();
204 ok
= data_cb(params
, data_cbarg
);
208 OPENSSL_free(pem_name
);
209 OPENSSL_free(pem_header
);
214 const OSSL_DISPATCH ossl_pem_to_der_decoder_functions
[] = {
215 { OSSL_FUNC_DECODER_NEWCTX
, (void (*)(void))pem2der_newctx
},
216 { OSSL_FUNC_DECODER_FREECTX
, (void (*)(void))pem2der_freectx
},
217 { OSSL_FUNC_DECODER_DECODE
, (void (*)(void))pem2der_decode
},