]>
Commit | Line | Data |
---|---|---|
62867571 | 1 | /* |
a28d06f3 | 2 | * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. |
1241126a | 3 | * |
16742672 | 4 | * Licensed under the Apache License 2.0 (the "License"). You may not use |
62867571 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 | |
1241126a DSH |
8 | */ |
9 | ||
10 | #include <stdio.h> | |
b39fc560 | 11 | #include "internal/cryptlib.h" |
97bb8dff | 12 | #include <openssl/core_dispatch.h> |
1241126a DSH |
13 | #include <openssl/buffer.h> |
14 | #include <openssl/objects.h> | |
15 | #include <openssl/evp.h> | |
1241126a DSH |
16 | #include <openssl/x509.h> |
17 | #include <openssl/pkcs12.h> | |
18 | #include <openssl/pem.h> | |
ece9304c | 19 | #include <openssl/encoder.h> |
1241126a | 20 | |
9fdcc21f | 21 | static int do_pk8pkey(BIO *bp, const EVP_PKEY *x, int isder, |
0f113f3e | 22 | int nid, const EVP_CIPHER *enc, |
de0799b0 | 23 | const char *kstr, int klen, |
97bb8dff | 24 | pem_password_cb *cb, void *u, |
b03da688 | 25 | const char *propq); |
984d6c60 DW |
26 | |
27 | #ifndef OPENSSL_NO_STDIO | |
9fdcc21f | 28 | static int do_pk8pkey_fp(FILE *bp, const EVP_PKEY *x, int isder, |
0f113f3e | 29 | int nid, const EVP_CIPHER *enc, |
de0799b0 | 30 | const char *kstr, int klen, |
97bb8dff | 31 | pem_password_cb *cb, void *u, |
b03da688 | 32 | const char *propq); |
984d6c60 | 33 | #endif |
0f113f3e MC |
34 | /* |
35 | * These functions write a private key in PKCS#8 format: it is a "drop in" | |
1241126a DSH |
36 | * replacement for PEM_write_bio_PrivateKey() and friends. As usual if 'enc' |
37 | * is NULL then it uses the unencrypted private key form. The 'nid' versions | |
38 | * uses PKCS#5 v1.5 PBE algorithms whereas the others use PKCS#5 v2.0. | |
39 | */ | |
40 | ||
9fdcc21f | 41 | int PEM_write_bio_PKCS8PrivateKey_nid(BIO *bp, const EVP_PKEY *x, int nid, |
de0799b0 | 42 | const char *kstr, int klen, |
0f113f3e | 43 | pem_password_cb *cb, void *u) |
1241126a | 44 | { |
b03da688 | 45 | return do_pk8pkey(bp, x, 0, nid, NULL, kstr, klen, cb, u, NULL); |
1241126a DSH |
46 | } |
47 | ||
9fdcc21f | 48 | int PEM_write_bio_PKCS8PrivateKey(BIO *bp, const EVP_PKEY *x, const EVP_CIPHER *enc, |
de0799b0 | 49 | const char *kstr, int klen, |
0f113f3e | 50 | pem_password_cb *cb, void *u) |
1241126a | 51 | { |
b03da688 | 52 | return do_pk8pkey(bp, x, 0, -1, enc, kstr, klen, cb, u, NULL); |
1241126a DSH |
53 | } |
54 | ||
9fdcc21f | 55 | int i2d_PKCS8PrivateKey_bio(BIO *bp, const EVP_PKEY *x, const EVP_CIPHER *enc, |
de0799b0 | 56 | const char *kstr, int klen, |
0f113f3e | 57 | pem_password_cb *cb, void *u) |
1241126a | 58 | { |
b03da688 | 59 | return do_pk8pkey(bp, x, 1, -1, enc, kstr, klen, cb, u, NULL); |
1241126a DSH |
60 | } |
61 | ||
9fdcc21f | 62 | int i2d_PKCS8PrivateKey_nid_bio(BIO *bp, const EVP_PKEY *x, int nid, |
de0799b0 | 63 | const char *kstr, int klen, |
0f113f3e | 64 | pem_password_cb *cb, void *u) |
1241126a | 65 | { |
b03da688 | 66 | return do_pk8pkey(bp, x, 1, nid, NULL, kstr, klen, cb, u, NULL); |
1241126a DSH |
67 | } |
68 | ||
9fdcc21f | 69 | static int do_pk8pkey(BIO *bp, const EVP_PKEY *x, int isder, int nid, |
de0799b0 | 70 | const EVP_CIPHER *enc, const char *kstr, int klen, |
b03da688 | 71 | pem_password_cb *cb, void *u, const char *propq) |
1241126a | 72 | { |
eb2bba25 | 73 | int ret = 0; |
97bb8dff RL |
74 | const char *outtype = isder ? "DER" : "PEM"; |
75 | OSSL_ENCODER_CTX *ctx = | |
fe75766c | 76 | OSSL_ENCODER_CTX_new_for_pkey(x, OSSL_KEYMGMT_SELECT_ALL, |
6a2b8ff3 | 77 | outtype, "PrivateKeyInfo", propq); |
75ebbd9a | 78 | |
eb2bba25 | 79 | if (ctx == NULL) |
0f113f3e | 80 | return 0; |
eb2bba25 RL |
81 | |
82 | /* | |
83 | * If no keystring or callback is set, OpenSSL traditionally uses the | |
84 | * user's cb argument as a password string, or if that's NULL, it falls | |
85 | * back on PEM_def_callback(). | |
86 | */ | |
87 | if (kstr == NULL && cb == NULL) { | |
88 | if (u != NULL) { | |
89 | kstr = u; | |
90 | klen = strlen(u); | |
91 | } else { | |
92 | cb = PEM_def_callback; | |
93 | } | |
0f113f3e | 94 | } |
0f113f3e | 95 | |
d29d7a7f SL |
96 | /* |
97 | * NOTE: There is no attempt to do a EVP_CIPHER_fetch() using the nid, | |
98 | * since the nid is a PBE algorithm which can't be fetched currently. | |
99 | * (e.g. NID_pbe_WithSHA1And2_Key_TripleDES_CBC). Just use the legacy | |
100 | * path if the NID is passed. | |
101 | */ | |
102 | if (nid == -1 && OSSL_ENCODER_CTX_get_num_encoders(ctx) != 0) { | |
eb2bba25 RL |
103 | ret = 1; |
104 | if (enc != NULL) { | |
105 | ret = 0; | |
ed576acd TM |
106 | if (OSSL_ENCODER_CTX_set_cipher(ctx, EVP_CIPHER_get0_name(enc), |
107 | NULL)) { | |
eb2bba25 RL |
108 | const unsigned char *ukstr = (const unsigned char *)kstr; |
109 | ||
110 | /* | |
111 | * Try to pass the passphrase if one was given, or the | |
112 | * passphrase callback if one was given. If none of them | |
113 | * are given and that's wrong, we rely on the _to_bio() | |
114 | * call to generate errors. | |
115 | */ | |
116 | ret = 1; | |
117 | if (kstr != NULL | |
ece9304c | 118 | && !OSSL_ENCODER_CTX_set_passphrase(ctx, ukstr, klen)) |
eb2bba25 RL |
119 | ret = 0; |
120 | else if (cb != NULL | |
97bb8dff | 121 | && !OSSL_ENCODER_CTX_set_pem_password_cb(ctx, cb, u)) |
eb2bba25 RL |
122 | ret = 0; |
123 | } | |
0f113f3e | 124 | } |
ece9304c | 125 | ret = ret && OSSL_ENCODER_to_bio(ctx, bp); |
0f113f3e | 126 | } else { |
eb2bba25 RL |
127 | X509_SIG *p8; |
128 | PKCS8_PRIV_KEY_INFO *p8inf; | |
129 | char buf[PEM_BUFSIZE]; | |
130 | ||
131 | ret = 0; | |
132 | if ((p8inf = EVP_PKEY2PKCS8(x)) == NULL) { | |
9311d0c4 | 133 | ERR_raise(ERR_LIB_PEM, PEM_R_ERROR_CONVERTING_PRIVATE_KEY); |
eb2bba25 RL |
134 | goto legacy_end; |
135 | } | |
136 | if (enc || (nid != -1)) { | |
137 | if (kstr == NULL) { | |
138 | klen = cb(buf, PEM_BUFSIZE, 1, u); | |
1d28ada1 | 139 | if (klen < 0) { |
9311d0c4 | 140 | ERR_raise(ERR_LIB_PEM, PEM_R_READ_KEY); |
eb2bba25 RL |
141 | goto legacy_end; |
142 | } | |
143 | ||
144 | kstr = buf; | |
145 | } | |
146 | p8 = PKCS8_encrypt(nid, enc, kstr, klen, NULL, 0, 0, p8inf); | |
147 | if (kstr == buf) | |
148 | OPENSSL_cleanse(buf, klen); | |
149 | if (p8 == NULL) | |
150 | goto legacy_end; | |
151 | if (isder) | |
152 | ret = i2d_PKCS8_bio(bp, p8); | |
153 | else | |
154 | ret = PEM_write_bio_PKCS8(bp, p8); | |
155 | X509_SIG_free(p8); | |
156 | } else { | |
157 | if (isder) | |
158 | ret = i2d_PKCS8_PRIV_KEY_INFO_bio(bp, p8inf); | |
159 | else | |
160 | ret = PEM_write_bio_PKCS8_PRIV_KEY_INFO(bp, p8inf); | |
161 | } | |
162 | legacy_end: | |
0f113f3e | 163 | PKCS8_PRIV_KEY_INFO_free(p8inf); |
0f113f3e | 164 | } |
ece9304c | 165 | OSSL_ENCODER_CTX_free(ctx); |
eb2bba25 | 166 | return ret; |
1241126a DSH |
167 | } |
168 | ||
0f113f3e MC |
169 | EVP_PKEY *d2i_PKCS8PrivateKey_bio(BIO *bp, EVP_PKEY **x, pem_password_cb *cb, |
170 | void *u) | |
1241126a | 171 | { |
0f113f3e MC |
172 | PKCS8_PRIV_KEY_INFO *p8inf = NULL; |
173 | X509_SIG *p8 = NULL; | |
174 | int klen; | |
175 | EVP_PKEY *ret; | |
176 | char psbuf[PEM_BUFSIZE]; | |
12a765a5 | 177 | |
0f113f3e | 178 | p8 = d2i_PKCS8_bio(bp, NULL); |
12a765a5 | 179 | if (p8 == NULL) |
0f113f3e | 180 | return NULL; |
12a765a5 | 181 | if (cb != NULL) |
0f113f3e MC |
182 | klen = cb(psbuf, PEM_BUFSIZE, 0, u); |
183 | else | |
184 | klen = PEM_def_callback(psbuf, PEM_BUFSIZE, 0, u); | |
c82c3462 | 185 | if (klen < 0) { |
9311d0c4 | 186 | ERR_raise(ERR_LIB_PEM, PEM_R_BAD_PASSWORD_READ); |
0f113f3e MC |
187 | X509_SIG_free(p8); |
188 | return NULL; | |
189 | } | |
190 | p8inf = PKCS8_decrypt(p8, psbuf, klen); | |
191 | X509_SIG_free(p8); | |
02fd47c8 | 192 | OPENSSL_cleanse(psbuf, klen); |
12a765a5 | 193 | if (p8inf == NULL) |
0f113f3e MC |
194 | return NULL; |
195 | ret = EVP_PKCS82PKEY(p8inf); | |
196 | PKCS8_PRIV_KEY_INFO_free(p8inf); | |
197 | if (!ret) | |
198 | return NULL; | |
12a765a5 | 199 | if (x != NULL) { |
c5ba2d99 | 200 | EVP_PKEY_free(*x); |
0f113f3e MC |
201 | *x = ret; |
202 | } | |
203 | return ret; | |
1241126a DSH |
204 | } |
205 | ||
4b618848 | 206 | #ifndef OPENSSL_NO_STDIO |
1241126a | 207 | |
9fdcc21f | 208 | int i2d_PKCS8PrivateKey_fp(FILE *fp, const EVP_PKEY *x, const EVP_CIPHER *enc, |
de0799b0 RL |
209 | const char *kstr, int klen, |
210 | pem_password_cb *cb, void *u) | |
1241126a | 211 | { |
b03da688 | 212 | return do_pk8pkey_fp(fp, x, 1, -1, enc, kstr, klen, cb, u, NULL); |
1241126a DSH |
213 | } |
214 | ||
9fdcc21f | 215 | int i2d_PKCS8PrivateKey_nid_fp(FILE *fp, const EVP_PKEY *x, int nid, |
de0799b0 | 216 | const char *kstr, int klen, |
0f113f3e | 217 | pem_password_cb *cb, void *u) |
1241126a | 218 | { |
b03da688 | 219 | return do_pk8pkey_fp(fp, x, 1, nid, NULL, kstr, klen, cb, u, NULL); |
1241126a DSH |
220 | } |
221 | ||
9fdcc21f | 222 | int PEM_write_PKCS8PrivateKey_nid(FILE *fp, const EVP_PKEY *x, int nid, |
de0799b0 | 223 | const char *kstr, int klen, |
0f113f3e | 224 | pem_password_cb *cb, void *u) |
1241126a | 225 | { |
b03da688 | 226 | return do_pk8pkey_fp(fp, x, 0, nid, NULL, kstr, klen, cb, u, NULL); |
1241126a DSH |
227 | } |
228 | ||
9fdcc21f | 229 | int PEM_write_PKCS8PrivateKey(FILE *fp, const EVP_PKEY *x, const EVP_CIPHER *enc, |
de0799b0 RL |
230 | const char *kstr, int klen, |
231 | pem_password_cb *cb, void *u) | |
1241126a | 232 | { |
b03da688 | 233 | return do_pk8pkey_fp(fp, x, 0, -1, enc, kstr, klen, cb, u, NULL); |
1241126a DSH |
234 | } |
235 | ||
9fdcc21f | 236 | static int do_pk8pkey_fp(FILE *fp, const EVP_PKEY *x, int isder, int nid, |
de0799b0 | 237 | const EVP_CIPHER *enc, const char *kstr, int klen, |
b03da688 | 238 | pem_password_cb *cb, void *u, const char *propq) |
1241126a | 239 | { |
0f113f3e MC |
240 | BIO *bp; |
241 | int ret; | |
75ebbd9a RS |
242 | |
243 | if ((bp = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) { | |
9311d0c4 | 244 | ERR_raise(ERR_LIB_PEM, ERR_R_BUF_LIB); |
26a7d938 | 245 | return 0; |
0f113f3e | 246 | } |
b03da688 | 247 | ret = do_pk8pkey(bp, x, isder, nid, enc, kstr, klen, cb, u, propq); |
0f113f3e MC |
248 | BIO_free(bp); |
249 | return ret; | |
1241126a DSH |
250 | } |
251 | ||
0f113f3e MC |
252 | EVP_PKEY *d2i_PKCS8PrivateKey_fp(FILE *fp, EVP_PKEY **x, pem_password_cb *cb, |
253 | void *u) | |
1241126a | 254 | { |
0f113f3e MC |
255 | BIO *bp; |
256 | EVP_PKEY *ret; | |
75ebbd9a RS |
257 | |
258 | if ((bp = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) { | |
9311d0c4 | 259 | ERR_raise(ERR_LIB_PEM, ERR_R_BUF_LIB); |
0f113f3e MC |
260 | return NULL; |
261 | } | |
262 | ret = d2i_PKCS8PrivateKey_bio(bp, x, cb, u); | |
263 | BIO_free(bp); | |
264 | return ret; | |
1241126a DSH |
265 | } |
266 | ||
267 | #endif | |
268 | ||
269 | IMPLEMENT_PEM_rw(PKCS8, X509_SIG, PEM_STRING_PKCS8, X509_SIG) | |
0f113f3e MC |
270 | |
271 | ||
1241126a | 272 | IMPLEMENT_PEM_rw(PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO, PEM_STRING_PKCS8INF, |
ece9304c | 273 | PKCS8_PRIV_KEY_INFO) |