]>
Commit | Line | Data |
---|---|---|
62867571 | 1 | /* |
00c405b3 | 2 | * Copyright 1995-2020 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 = | |
4227e504 | 76 | OSSL_ENCODER_CTX_new_by_EVP_PKEY(x, OSSL_KEYMGMT_SELECT_ALL, |
b03da688 | 77 | outtype, "pkcs8", 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 | |
97bb8dff | 96 | if (OSSL_ENCODER_CTX_get_num_encoders(ctx) != 0) { |
eb2bba25 RL |
97 | ret = 1; |
98 | if (enc != NULL) { | |
99 | ret = 0; | |
ece9304c | 100 | if (OSSL_ENCODER_CTX_set_cipher(ctx, EVP_CIPHER_name(enc), NULL)) { |
eb2bba25 RL |
101 | const unsigned char *ukstr = (const unsigned char *)kstr; |
102 | ||
103 | /* | |
104 | * Try to pass the passphrase if one was given, or the | |
105 | * passphrase callback if one was given. If none of them | |
106 | * are given and that's wrong, we rely on the _to_bio() | |
107 | * call to generate errors. | |
108 | */ | |
109 | ret = 1; | |
110 | if (kstr != NULL | |
ece9304c | 111 | && !OSSL_ENCODER_CTX_set_passphrase(ctx, ukstr, klen)) |
eb2bba25 RL |
112 | ret = 0; |
113 | else if (cb != NULL | |
97bb8dff | 114 | && !OSSL_ENCODER_CTX_set_pem_password_cb(ctx, cb, u)) |
eb2bba25 RL |
115 | ret = 0; |
116 | } | |
0f113f3e | 117 | } |
ece9304c | 118 | ret = ret && OSSL_ENCODER_to_bio(ctx, bp); |
0f113f3e | 119 | } else { |
eb2bba25 RL |
120 | X509_SIG *p8; |
121 | PKCS8_PRIV_KEY_INFO *p8inf; | |
122 | char buf[PEM_BUFSIZE]; | |
123 | ||
124 | ret = 0; | |
125 | if ((p8inf = EVP_PKEY2PKCS8(x)) == NULL) { | |
9311d0c4 | 126 | ERR_raise(ERR_LIB_PEM, PEM_R_ERROR_CONVERTING_PRIVATE_KEY); |
eb2bba25 RL |
127 | goto legacy_end; |
128 | } | |
129 | if (enc || (nid != -1)) { | |
130 | if (kstr == NULL) { | |
131 | klen = cb(buf, PEM_BUFSIZE, 1, u); | |
132 | if (klen <= 0) { | |
9311d0c4 | 133 | ERR_raise(ERR_LIB_PEM, PEM_R_READ_KEY); |
eb2bba25 RL |
134 | goto legacy_end; |
135 | } | |
136 | ||
137 | kstr = buf; | |
138 | } | |
139 | p8 = PKCS8_encrypt(nid, enc, kstr, klen, NULL, 0, 0, p8inf); | |
140 | if (kstr == buf) | |
141 | OPENSSL_cleanse(buf, klen); | |
142 | if (p8 == NULL) | |
143 | goto legacy_end; | |
144 | if (isder) | |
145 | ret = i2d_PKCS8_bio(bp, p8); | |
146 | else | |
147 | ret = PEM_write_bio_PKCS8(bp, p8); | |
148 | X509_SIG_free(p8); | |
149 | } else { | |
150 | if (isder) | |
151 | ret = i2d_PKCS8_PRIV_KEY_INFO_bio(bp, p8inf); | |
152 | else | |
153 | ret = PEM_write_bio_PKCS8_PRIV_KEY_INFO(bp, p8inf); | |
154 | } | |
155 | legacy_end: | |
0f113f3e | 156 | PKCS8_PRIV_KEY_INFO_free(p8inf); |
0f113f3e | 157 | } |
ece9304c | 158 | OSSL_ENCODER_CTX_free(ctx); |
eb2bba25 | 159 | return ret; |
1241126a DSH |
160 | } |
161 | ||
0f113f3e MC |
162 | EVP_PKEY *d2i_PKCS8PrivateKey_bio(BIO *bp, EVP_PKEY **x, pem_password_cb *cb, |
163 | void *u) | |
1241126a | 164 | { |
0f113f3e MC |
165 | PKCS8_PRIV_KEY_INFO *p8inf = NULL; |
166 | X509_SIG *p8 = NULL; | |
167 | int klen; | |
168 | EVP_PKEY *ret; | |
169 | char psbuf[PEM_BUFSIZE]; | |
12a765a5 | 170 | |
0f113f3e | 171 | p8 = d2i_PKCS8_bio(bp, NULL); |
12a765a5 | 172 | if (p8 == NULL) |
0f113f3e | 173 | return NULL; |
12a765a5 | 174 | if (cb != NULL) |
0f113f3e MC |
175 | klen = cb(psbuf, PEM_BUFSIZE, 0, u); |
176 | else | |
177 | klen = PEM_def_callback(psbuf, PEM_BUFSIZE, 0, u); | |
c82c3462 | 178 | if (klen < 0) { |
9311d0c4 | 179 | ERR_raise(ERR_LIB_PEM, PEM_R_BAD_PASSWORD_READ); |
0f113f3e MC |
180 | X509_SIG_free(p8); |
181 | return NULL; | |
182 | } | |
183 | p8inf = PKCS8_decrypt(p8, psbuf, klen); | |
184 | X509_SIG_free(p8); | |
02fd47c8 | 185 | OPENSSL_cleanse(psbuf, klen); |
12a765a5 | 186 | if (p8inf == NULL) |
0f113f3e MC |
187 | return NULL; |
188 | ret = EVP_PKCS82PKEY(p8inf); | |
189 | PKCS8_PRIV_KEY_INFO_free(p8inf); | |
190 | if (!ret) | |
191 | return NULL; | |
12a765a5 | 192 | if (x != NULL) { |
c5ba2d99 | 193 | EVP_PKEY_free(*x); |
0f113f3e MC |
194 | *x = ret; |
195 | } | |
196 | return ret; | |
1241126a DSH |
197 | } |
198 | ||
4b618848 | 199 | #ifndef OPENSSL_NO_STDIO |
1241126a | 200 | |
9fdcc21f | 201 | int i2d_PKCS8PrivateKey_fp(FILE *fp, const EVP_PKEY *x, const EVP_CIPHER *enc, |
de0799b0 RL |
202 | const char *kstr, int klen, |
203 | pem_password_cb *cb, void *u) | |
1241126a | 204 | { |
b03da688 | 205 | return do_pk8pkey_fp(fp, x, 1, -1, enc, kstr, klen, cb, u, NULL); |
1241126a DSH |
206 | } |
207 | ||
9fdcc21f | 208 | int i2d_PKCS8PrivateKey_nid_fp(FILE *fp, const EVP_PKEY *x, int nid, |
de0799b0 | 209 | const char *kstr, int klen, |
0f113f3e | 210 | pem_password_cb *cb, void *u) |
1241126a | 211 | { |
b03da688 | 212 | return do_pk8pkey_fp(fp, x, 1, nid, NULL, kstr, klen, cb, u, NULL); |
1241126a DSH |
213 | } |
214 | ||
9fdcc21f | 215 | int PEM_write_PKCS8PrivateKey_nid(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, 0, nid, NULL, kstr, klen, cb, u, NULL); |
1241126a DSH |
220 | } |
221 | ||
9fdcc21f | 222 | int PEM_write_PKCS8PrivateKey(FILE *fp, const EVP_PKEY *x, const EVP_CIPHER *enc, |
de0799b0 RL |
223 | const char *kstr, int klen, |
224 | pem_password_cb *cb, void *u) | |
1241126a | 225 | { |
b03da688 | 226 | return do_pk8pkey_fp(fp, x, 0, -1, enc, kstr, klen, cb, u, NULL); |
1241126a DSH |
227 | } |
228 | ||
9fdcc21f | 229 | static int do_pk8pkey_fp(FILE *fp, const EVP_PKEY *x, int isder, int nid, |
de0799b0 | 230 | const EVP_CIPHER *enc, const char *kstr, int klen, |
b03da688 | 231 | pem_password_cb *cb, void *u, const char *propq) |
1241126a | 232 | { |
0f113f3e MC |
233 | BIO *bp; |
234 | int ret; | |
75ebbd9a RS |
235 | |
236 | if ((bp = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) { | |
9311d0c4 | 237 | ERR_raise(ERR_LIB_PEM, ERR_R_BUF_LIB); |
26a7d938 | 238 | return 0; |
0f113f3e | 239 | } |
b03da688 | 240 | ret = do_pk8pkey(bp, x, isder, nid, enc, kstr, klen, cb, u, propq); |
0f113f3e MC |
241 | BIO_free(bp); |
242 | return ret; | |
1241126a DSH |
243 | } |
244 | ||
0f113f3e MC |
245 | EVP_PKEY *d2i_PKCS8PrivateKey_fp(FILE *fp, EVP_PKEY **x, pem_password_cb *cb, |
246 | void *u) | |
1241126a | 247 | { |
0f113f3e MC |
248 | BIO *bp; |
249 | EVP_PKEY *ret; | |
75ebbd9a RS |
250 | |
251 | if ((bp = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) { | |
9311d0c4 | 252 | ERR_raise(ERR_LIB_PEM, ERR_R_BUF_LIB); |
0f113f3e MC |
253 | return NULL; |
254 | } | |
255 | ret = d2i_PKCS8PrivateKey_bio(bp, x, cb, u); | |
256 | BIO_free(bp); | |
257 | return ret; | |
1241126a DSH |
258 | } |
259 | ||
260 | #endif | |
261 | ||
262 | IMPLEMENT_PEM_rw(PKCS8, X509_SIG, PEM_STRING_PKCS8, X509_SIG) | |
0f113f3e MC |
263 | |
264 | ||
1241126a | 265 | IMPLEMENT_PEM_rw(PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO, PEM_STRING_PKCS8INF, |
ece9304c | 266 | PKCS8_PRIV_KEY_INFO) |