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