]>
Commit | Line | Data |
---|---|---|
0f113f3e | 1 | /* |
da1c088f | 2 | * Copyright 1999-2023 The OpenSSL Project Authors. All Rights Reserved. |
cfcefcbe | 3 | * |
4a8b0c55 | 4 | * Licensed under the Apache License 2.0 (the "License"). You may not use |
aa6bb135 RS |
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 | |
cfcefcbe DSH |
8 | */ |
9 | ||
10 | #include <stdio.h> | |
11 | #include <stdlib.h> | |
b39fc560 | 12 | #include "internal/cryptlib.h" |
ec577822 BM |
13 | #include <openssl/x509.h> |
14 | #include <openssl/rand.h> | |
31a6b52f | 15 | #include <openssl/encoder.h> |
4f0831b8 | 16 | #include <openssl/decoder.h> |
31a6b52f | 17 | #include "internal/provider.h" |
52ce351a | 18 | #include "internal/sizes.h" |
25f2138b DMSP |
19 | #include "crypto/asn1.h" |
20 | #include "crypto/evp.h" | |
21 | #include "crypto/x509.h" | |
cfcefcbe DSH |
22 | |
23 | /* Extract a private key from a PKCS8 structure */ | |
24 | ||
4f0831b8 TM |
25 | EVP_PKEY *evp_pkcs82pkey_legacy(const PKCS8_PRIV_KEY_INFO *p8, OSSL_LIB_CTX *libctx, |
26 | const char *propq) | |
cfcefcbe | 27 | { |
0f113f3e | 28 | EVP_PKEY *pkey = NULL; |
245c6bc3 | 29 | const ASN1_OBJECT *algoid; |
0f113f3e MC |
30 | char obj_tmp[80]; |
31 | ||
32 | if (!PKCS8_pkey_get0(&algoid, NULL, NULL, NULL, p8)) | |
33 | return NULL; | |
34 | ||
75ebbd9a | 35 | if ((pkey = EVP_PKEY_new()) == NULL) { |
e077455e | 36 | ERR_raise(ERR_LIB_EVP, ERR_R_EVP_LIB); |
0f113f3e MC |
37 | return NULL; |
38 | } | |
39 | ||
40 | if (!EVP_PKEY_set_type(pkey, OBJ_obj2nid(algoid))) { | |
0f113f3e | 41 | i2t_ASN1_OBJECT(obj_tmp, 80, algoid); |
a150f8e1 RL |
42 | ERR_raise_data(ERR_LIB_EVP, EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM, |
43 | "TYPE=%s", obj_tmp); | |
0f113f3e MC |
44 | goto error; |
45 | } | |
46 | ||
d8652be0 MC |
47 | if (pkey->ameth->priv_decode_ex != NULL) { |
48 | if (!pkey->ameth->priv_decode_ex(pkey, p8, libctx, propq)) | |
472a88b7 | 49 | goto error; |
472a88b7 | 50 | } else if (pkey->ameth->priv_decode != NULL) { |
0f113f3e | 51 | if (!pkey->ameth->priv_decode(pkey, p8)) { |
9311d0c4 | 52 | ERR_raise(ERR_LIB_EVP, EVP_R_PRIVATE_KEY_DECODE_ERROR); |
0f113f3e MC |
53 | goto error; |
54 | } | |
55 | } else { | |
9311d0c4 | 56 | ERR_raise(ERR_LIB_EVP, EVP_R_METHOD_NOT_SUPPORTED); |
0f113f3e MC |
57 | goto error; |
58 | } | |
59 | ||
60 | return pkey; | |
61 | ||
62 | error: | |
63 | EVP_PKEY_free(pkey); | |
64 | return NULL; | |
cfcefcbe DSH |
65 | } |
66 | ||
4f0831b8 TM |
67 | EVP_PKEY *EVP_PKCS82PKEY_ex(const PKCS8_PRIV_KEY_INFO *p8, OSSL_LIB_CTX *libctx, |
68 | const char *propq) | |
69 | { | |
70 | EVP_PKEY *pkey = NULL; | |
71 | const unsigned char *p8_data = NULL; | |
72 | unsigned char *encoded_data = NULL; | |
73 | int encoded_len; | |
69e14a54 | 74 | int selection; |
4f0831b8 TM |
75 | size_t len; |
76 | OSSL_DECODER_CTX *dctx = NULL; | |
52ce351a MC |
77 | const ASN1_OBJECT *algoid = NULL; |
78 | char keytype[OSSL_MAX_NAME_SIZE]; | |
79 | ||
80 | if (p8 == NULL | |
81 | || !PKCS8_pkey_get0(&algoid, NULL, NULL, NULL, p8) | |
82 | || !OBJ_obj2txt(keytype, sizeof(keytype), algoid, 0)) | |
83 | return NULL; | |
4f0831b8 | 84 | |
ec3dd970 P |
85 | if ((encoded_len = i2d_PKCS8_PRIV_KEY_INFO(p8, &encoded_data)) <= 0 |
86 | || encoded_data == NULL) | |
87 | return NULL; | |
4f0831b8 TM |
88 | |
89 | p8_data = encoded_data; | |
90 | len = encoded_len; | |
69e14a54 | 91 | selection = EVP_PKEY_KEYPAIR | EVP_PKEY_KEY_PARAMETERS; |
6a2b8ff3 | 92 | dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, "DER", "PrivateKeyInfo", |
52ce351a MC |
93 | keytype, selection, libctx, propq); |
94 | ||
95 | if (dctx != NULL && OSSL_DECODER_CTX_get_num_decoders(dctx) == 0) { | |
96 | OSSL_DECODER_CTX_free(dctx); | |
97 | ||
98 | /* | |
99 | * This could happen if OBJ_obj2txt() returned a text OID and the | |
100 | * decoder has not got that OID as an alias. We fall back to a NULL | |
101 | * keytype | |
102 | */ | |
103 | dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, "DER", "PrivateKeyInfo", | |
104 | NULL, selection, libctx, propq); | |
105 | } | |
106 | ||
4f0831b8 TM |
107 | if (dctx == NULL |
108 | || !OSSL_DECODER_from_data(dctx, &p8_data, &len)) | |
109 | /* try legacy */ | |
110 | pkey = evp_pkcs82pkey_legacy(p8, libctx, propq); | |
111 | ||
4f0831b8 TM |
112 | OPENSSL_clear_free(encoded_data, encoded_len); |
113 | OSSL_DECODER_CTX_free(dctx); | |
114 | return pkey; | |
115 | } | |
116 | ||
472a88b7 MC |
117 | EVP_PKEY *EVP_PKCS82PKEY(const PKCS8_PRIV_KEY_INFO *p8) |
118 | { | |
d8652be0 | 119 | return EVP_PKCS82PKEY_ex(p8, NULL, NULL); |
472a88b7 MC |
120 | } |
121 | ||
cfcefcbe DSH |
122 | /* Turn a private key into a PKCS8 structure */ |
123 | ||
9fdcc21f | 124 | PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8(const EVP_PKEY *pkey) |
cfcefcbe | 125 | { |
31a6b52f RL |
126 | PKCS8_PRIV_KEY_INFO *p8 = NULL; |
127 | OSSL_ENCODER_CTX *ctx = NULL; | |
128 | ||
129 | /* | |
130 | * The implementation for provider-native keys is to encode the | |
131 | * key to a DER encoded PKCS#8 structure, then convert it to a | |
132 | * PKCS8_PRIV_KEY_INFO with good old d2i functions. | |
133 | */ | |
134 | if (evp_pkey_is_provided(pkey)) { | |
135 | int selection = OSSL_KEYMGMT_SELECT_ALL; | |
31a6b52f RL |
136 | unsigned char *der = NULL; |
137 | size_t derlen = 0; | |
138 | const unsigned char *pp; | |
139 | ||
fe75766c | 140 | if ((ctx = OSSL_ENCODER_CTX_new_for_pkey(pkey, selection, |
6a2b8ff3 | 141 | "DER", "PrivateKeyInfo", |
fe75766c | 142 | NULL)) == NULL |
31a6b52f RL |
143 | || !OSSL_ENCODER_to_data(ctx, &der, &derlen)) |
144 | goto error; | |
0f113f3e | 145 | |
31a6b52f RL |
146 | pp = der; |
147 | p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, &pp, (long)derlen); | |
148 | OPENSSL_free(der); | |
149 | if (p8 == NULL) | |
150 | goto error; | |
151 | } else { | |
152 | p8 = PKCS8_PRIV_KEY_INFO_new(); | |
153 | if (p8 == NULL) { | |
e077455e | 154 | ERR_raise(ERR_LIB_EVP, ERR_R_ASN1_LIB); |
31a6b52f RL |
155 | return NULL; |
156 | } | |
b5275648 | 157 | |
31a6b52f RL |
158 | if (pkey->ameth != NULL) { |
159 | if (pkey->ameth->priv_encode != NULL) { | |
160 | if (!pkey->ameth->priv_encode(p8, pkey)) { | |
9311d0c4 | 161 | ERR_raise(ERR_LIB_EVP, EVP_R_PRIVATE_KEY_ENCODE_ERROR); |
31a6b52f RL |
162 | goto error; |
163 | } | |
164 | } else { | |
9311d0c4 | 165 | ERR_raise(ERR_LIB_EVP, EVP_R_METHOD_NOT_SUPPORTED); |
0f113f3e MC |
166 | goto error; |
167 | } | |
168 | } else { | |
9311d0c4 | 169 | ERR_raise(ERR_LIB_EVP, EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM); |
0f113f3e MC |
170 | goto error; |
171 | } | |
0f113f3e | 172 | } |
31a6b52f | 173 | goto end; |
0f113f3e MC |
174 | error: |
175 | PKCS8_PRIV_KEY_INFO_free(p8); | |
31a6b52f RL |
176 | p8 = NULL; |
177 | end: | |
178 | OSSL_ENCODER_CTX_free(ctx); | |
179 | return p8; | |
180 | ||
cfcefcbe DSH |
181 | } |
182 | ||
b6995add DSH |
183 | /* EVP_PKEY attribute functions */ |
184 | ||
185 | int EVP_PKEY_get_attr_count(const EVP_PKEY *key) | |
186 | { | |
0f113f3e | 187 | return X509at_get_attr_count(key->attributes); |
b6995add DSH |
188 | } |
189 | ||
0f113f3e | 190 | int EVP_PKEY_get_attr_by_NID(const EVP_PKEY *key, int nid, int lastpos) |
b6995add | 191 | { |
0f113f3e | 192 | return X509at_get_attr_by_NID(key->attributes, nid, lastpos); |
b6995add DSH |
193 | } |
194 | ||
c47ba4e9 | 195 | int EVP_PKEY_get_attr_by_OBJ(const EVP_PKEY *key, const ASN1_OBJECT *obj, |
0f113f3e | 196 | int lastpos) |
b6995add | 197 | { |
0f113f3e | 198 | return X509at_get_attr_by_OBJ(key->attributes, obj, lastpos); |
b6995add DSH |
199 | } |
200 | ||
201 | X509_ATTRIBUTE *EVP_PKEY_get_attr(const EVP_PKEY *key, int loc) | |
202 | { | |
0f113f3e | 203 | return X509at_get_attr(key->attributes, loc); |
b6995add DSH |
204 | } |
205 | ||
206 | X509_ATTRIBUTE *EVP_PKEY_delete_attr(EVP_PKEY *key, int loc) | |
207 | { | |
0f113f3e | 208 | return X509at_delete_attr(key->attributes, loc); |
b6995add DSH |
209 | } |
210 | ||
211 | int EVP_PKEY_add1_attr(EVP_PKEY *key, X509_ATTRIBUTE *attr) | |
212 | { | |
0f113f3e MC |
213 | if (X509at_add1_attr(&key->attributes, attr)) |
214 | return 1; | |
215 | return 0; | |
b6995add DSH |
216 | } |
217 | ||
218 | int EVP_PKEY_add1_attr_by_OBJ(EVP_PKEY *key, | |
0f113f3e MC |
219 | const ASN1_OBJECT *obj, int type, |
220 | const unsigned char *bytes, int len) | |
b6995add | 221 | { |
0f113f3e MC |
222 | if (X509at_add1_attr_by_OBJ(&key->attributes, obj, type, bytes, len)) |
223 | return 1; | |
224 | return 0; | |
b6995add DSH |
225 | } |
226 | ||
227 | int EVP_PKEY_add1_attr_by_NID(EVP_PKEY *key, | |
0f113f3e MC |
228 | int nid, int type, |
229 | const unsigned char *bytes, int len) | |
b6995add | 230 | { |
0f113f3e MC |
231 | if (X509at_add1_attr_by_NID(&key->attributes, nid, type, bytes, len)) |
232 | return 1; | |
233 | return 0; | |
b6995add DSH |
234 | } |
235 | ||
236 | int EVP_PKEY_add1_attr_by_txt(EVP_PKEY *key, | |
0f113f3e MC |
237 | const char *attrname, int type, |
238 | const unsigned char *bytes, int len) | |
b6995add | 239 | { |
0f113f3e MC |
240 | if (X509at_add1_attr_by_txt(&key->attributes, attrname, type, bytes, len)) |
241 | return 1; | |
242 | return 0; | |
b6995add | 243 | } |
d8025f4a | 244 | |
ddf0d149 | 245 | const char *EVP_PKEY_get0_type_name(const EVP_PKEY *key) |
d8025f4a MC |
246 | { |
247 | const EVP_PKEY_ASN1_METHOD *ameth; | |
248 | const char *name = NULL; | |
249 | ||
250 | if (key->keymgmt != NULL) | |
ed576acd | 251 | return EVP_KEYMGMT_get0_name(key->keymgmt); |
d8025f4a MC |
252 | |
253 | /* Otherwise fallback to legacy */ | |
254 | ameth = EVP_PKEY_get0_asn1(key); | |
255 | if (ameth != NULL) | |
256 | EVP_PKEY_asn1_get0_info(NULL, NULL, | |
257 | NULL, NULL, &name, ameth); | |
258 | ||
259 | return name; | |
260 | } | |
ad0a2c01 RL |
261 | |
262 | const OSSL_PROVIDER *EVP_PKEY_get0_provider(const EVP_PKEY *key) | |
263 | { | |
264 | if (evp_pkey_is_provided(key)) | |
265 | return EVP_KEYMGMT_get0_provider(key->keymgmt); | |
266 | return NULL; | |
267 | } |