]>
Commit | Line | Data |
---|---|---|
d02b48c6 | 1 | /* crypto/asn1/n_pkey.c */ |
58964a49 | 2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) |
d02b48c6 RE |
3 | * All rights reserved. |
4 | * | |
5 | * This package is an SSL implementation written | |
6 | * by Eric Young (eay@cryptsoft.com). | |
7 | * The implementation was written so as to conform with Netscapes SSL. | |
40720ce3 | 8 | * |
d02b48c6 RE |
9 | * This library is free for commercial and non-commercial use as long as |
10 | * the following conditions are aheared to. The following conditions | |
11 | * apply to all code found in this distribution, be it the RC4, RSA, | |
12 | * lhash, DES, etc., code; not just the SSL code. The SSL documentation | |
13 | * included with this distribution is covered by the same copyright terms | |
14 | * except that the holder is Tim Hudson (tjh@cryptsoft.com). | |
40720ce3 | 15 | * |
d02b48c6 RE |
16 | * Copyright remains Eric Young's, and as such any Copyright notices in |
17 | * the code are not to be removed. | |
18 | * If this package is used in a product, Eric Young should be given attribution | |
19 | * as the author of the parts of the library used. | |
20 | * This can be in the form of a textual message at program startup or | |
21 | * in documentation (online or textual) provided with the package. | |
40720ce3 | 22 | * |
d02b48c6 RE |
23 | * Redistribution and use in source and binary forms, with or without |
24 | * modification, are permitted provided that the following conditions | |
25 | * are met: | |
26 | * 1. Redistributions of source code must retain the copyright | |
27 | * notice, this list of conditions and the following disclaimer. | |
28 | * 2. Redistributions in binary form must reproduce the above copyright | |
29 | * notice, this list of conditions and the following disclaimer in the | |
30 | * documentation and/or other materials provided with the distribution. | |
31 | * 3. All advertising materials mentioning features or use of this software | |
32 | * must display the following acknowledgement: | |
33 | * "This product includes cryptographic software written by | |
34 | * Eric Young (eay@cryptsoft.com)" | |
35 | * The word 'cryptographic' can be left out if the rouines from the library | |
36 | * being used are not cryptographic related :-). | |
40720ce3 | 37 | * 4. If you include any Windows specific code (or a derivative thereof) from |
d02b48c6 RE |
38 | * the apps directory (application code) you must include an acknowledgement: |
39 | * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" | |
40720ce3 | 40 | * |
d02b48c6 RE |
41 | * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND |
42 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
43 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
44 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
45 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
46 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
47 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
48 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
49 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
50 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
51 | * SUCH DAMAGE. | |
40720ce3 | 52 | * |
d02b48c6 RE |
53 | * The licence and distribution terms for any publically available version or |
54 | * derivative of this code cannot be changed. i.e. this code cannot simply be | |
55 | * copied and put under another distribution licence | |
56 | * [including the GNU Public Licence.] | |
57 | */ | |
58 | ||
59 | #include <stdio.h> | |
60 | #include "cryptlib.h" | |
536b73e7 | 61 | #ifndef OPENSSL_NO_RSA |
40720ce3 MC |
62 | # include <openssl/rsa.h> |
63 | # include <openssl/objects.h> | |
64 | # include <openssl/asn1t.h> | |
65 | # include <openssl/asn1_mac.h> | |
66 | # include <openssl/evp.h> | |
67 | # include <openssl/x509.h> | |
68 | ||
69 | # ifndef OPENSSL_NO_RC4 | |
70 | ||
71 | typedef struct netscape_pkey_st { | |
72 | long version; | |
73 | X509_ALGOR *algor; | |
74 | ASN1_OCTET_STRING *private_key; | |
75 | } NETSCAPE_PKEY; | |
76 | ||
77 | typedef struct netscape_encrypted_pkey_st { | |
78 | ASN1_OCTET_STRING *os; | |
79 | /* | |
80 | * This is the same structure as DigestInfo so use it: although this | |
81 | * isn't really anything to do with digests. | |
82 | */ | |
83 | X509_SIG *enckey; | |
84 | } NETSCAPE_ENCRYPTED_PKEY; | |
9d6b1ce6 DSH |
85 | |
86 | ||
87 | ASN1_BROKEN_SEQUENCE(NETSCAPE_ENCRYPTED_PKEY) = { | |
40720ce3 MC |
88 | ASN1_SIMPLE(NETSCAPE_ENCRYPTED_PKEY, os, ASN1_OCTET_STRING), |
89 | ASN1_SIMPLE(NETSCAPE_ENCRYPTED_PKEY, enckey, X509_SIG) | |
d339187b | 90 | } ASN1_BROKEN_SEQUENCE_END(NETSCAPE_ENCRYPTED_PKEY) |
9d6b1ce6 | 91 | |
65ee74fb LJ |
92 | DECLARE_ASN1_FUNCTIONS_const(NETSCAPE_ENCRYPTED_PKEY) |
93 | DECLARE_ASN1_ENCODE_FUNCTIONS_const(NETSCAPE_ENCRYPTED_PKEY,NETSCAPE_ENCRYPTED_PKEY) | |
9d6b1ce6 DSH |
94 | IMPLEMENT_ASN1_FUNCTIONS_const(NETSCAPE_ENCRYPTED_PKEY) |
95 | ||
96 | ASN1_SEQUENCE(NETSCAPE_PKEY) = { | |
40720ce3 MC |
97 | ASN1_SIMPLE(NETSCAPE_PKEY, version, LONG), |
98 | ASN1_SIMPLE(NETSCAPE_PKEY, algor, X509_ALGOR), | |
99 | ASN1_SIMPLE(NETSCAPE_PKEY, private_key, ASN1_OCTET_STRING) | |
d339187b | 100 | } ASN1_SEQUENCE_END(NETSCAPE_PKEY) |
9d6b1ce6 | 101 | |
65ee74fb LJ |
102 | DECLARE_ASN1_FUNCTIONS_const(NETSCAPE_PKEY) |
103 | DECLARE_ASN1_ENCODE_FUNCTIONS_const(NETSCAPE_PKEY,NETSCAPE_PKEY) | |
9d6b1ce6 DSH |
104 | IMPLEMENT_ASN1_FUNCTIONS_const(NETSCAPE_PKEY) |
105 | ||
106 | static RSA *d2i_RSA_NET_2(RSA **a, ASN1_OCTET_STRING *os, | |
40720ce3 MC |
107 | int (*cb) (char *buf, int len, const char *prompt, |
108 | int verify), int sgckey); | |
f5d7a031 | 109 | |
41a15c4f | 110 | int i2d_Netscape_RSA(const RSA *a, unsigned char **pp, |
40720ce3 MC |
111 | int (*cb) (char *buf, int len, const char *prompt, |
112 | int verify)) | |
d3ed8ceb | 113 | { |
40720ce3 | 114 | return i2d_RSA_NET(a, pp, cb, 0); |
d3ed8ceb DSH |
115 | } |
116 | ||
41a15c4f | 117 | int i2d_RSA_NET(const RSA *a, unsigned char **pp, |
40720ce3 MC |
118 | int (*cb) (char *buf, int len, const char *prompt, |
119 | int verify), int sgckey) | |
120 | { | |
121 | int i, j, ret = 0; | |
122 | int rsalen, pkeylen, olen; | |
123 | NETSCAPE_PKEY *pkey = NULL; | |
124 | NETSCAPE_ENCRYPTED_PKEY *enckey = NULL; | |
125 | unsigned char buf[256], *zz; | |
126 | unsigned char key[EVP_MAX_KEY_LENGTH]; | |
127 | EVP_CIPHER_CTX ctx; | |
128 | ||
129 | if (a == NULL) | |
130 | return (0); | |
131 | ||
132 | if ((pkey = NETSCAPE_PKEY_new()) == NULL) | |
133 | goto err; | |
134 | if ((enckey = NETSCAPE_ENCRYPTED_PKEY_new()) == NULL) | |
135 | goto err; | |
136 | pkey->version = 0; | |
137 | ||
138 | pkey->algor->algorithm = OBJ_nid2obj(NID_rsaEncryption); | |
139 | if ((pkey->algor->parameter = ASN1_TYPE_new()) == NULL) | |
140 | goto err; | |
141 | pkey->algor->parameter->type = V_ASN1_NULL; | |
142 | ||
143 | rsalen = i2d_RSAPrivateKey(a, NULL); | |
144 | ||
145 | /* | |
146 | * Fake some octet strings just for the initial length calculation. | |
147 | */ | |
148 | ||
149 | pkey->private_key->length = rsalen; | |
150 | ||
151 | pkeylen = i2d_NETSCAPE_PKEY(pkey, NULL); | |
152 | ||
153 | enckey->enckey->digest->length = pkeylen; | |
154 | ||
155 | enckey->os->length = 11; /* "private-key" */ | |
156 | ||
157 | enckey->enckey->algor->algorithm = OBJ_nid2obj(NID_rc4); | |
158 | if ((enckey->enckey->algor->parameter = ASN1_TYPE_new()) == NULL) | |
159 | goto err; | |
160 | enckey->enckey->algor->parameter->type = V_ASN1_NULL; | |
161 | ||
162 | if (pp == NULL) { | |
163 | olen = i2d_NETSCAPE_ENCRYPTED_PKEY(enckey, NULL); | |
164 | NETSCAPE_PKEY_free(pkey); | |
165 | NETSCAPE_ENCRYPTED_PKEY_free(enckey); | |
166 | return olen; | |
167 | } | |
168 | ||
169 | /* Since its RC4 encrypted length is actual length */ | |
170 | if ((zz = (unsigned char *)OPENSSL_malloc(rsalen)) == NULL) { | |
171 | ASN1err(ASN1_F_I2D_RSA_NET, ERR_R_MALLOC_FAILURE); | |
172 | goto err; | |
173 | } | |
174 | ||
175 | pkey->private_key->data = zz; | |
176 | /* Write out private key encoding */ | |
177 | i2d_RSAPrivateKey(a, &zz); | |
178 | ||
179 | if ((zz = OPENSSL_malloc(pkeylen)) == NULL) { | |
180 | ASN1err(ASN1_F_I2D_RSA_NET, ERR_R_MALLOC_FAILURE); | |
181 | goto err; | |
182 | } | |
183 | ||
184 | if (!ASN1_STRING_set(enckey->os, "private-key", -1)) { | |
185 | ASN1err(ASN1_F_I2D_RSA_NET, ERR_R_MALLOC_FAILURE); | |
186 | goto err; | |
187 | } | |
188 | enckey->enckey->digest->data = zz; | |
189 | i2d_NETSCAPE_PKEY(pkey, &zz); | |
190 | ||
191 | /* Wipe the private key encoding */ | |
192 | OPENSSL_cleanse(pkey->private_key->data, rsalen); | |
193 | ||
194 | if (cb == NULL) | |
195 | cb = EVP_read_pw_string; | |
196 | i = cb((char *)buf, 256, "Enter Private Key password:", 1); | |
197 | if (i != 0) { | |
198 | ASN1err(ASN1_F_I2D_RSA_NET, ASN1_R_BAD_PASSWORD_READ); | |
199 | goto err; | |
200 | } | |
201 | i = strlen((char *)buf); | |
202 | /* If the key is used for SGC the algorithm is modified a little. */ | |
203 | if (sgckey) { | |
204 | EVP_Digest(buf, i, buf, NULL, EVP_md5(), NULL); | |
205 | memcpy(buf + 16, "SGCKEYSALT", 10); | |
206 | i = 26; | |
207 | } | |
208 | ||
209 | EVP_BytesToKey(EVP_rc4(), EVP_md5(), NULL, buf, i, 1, key, NULL); | |
210 | OPENSSL_cleanse(buf, 256); | |
211 | ||
212 | /* Encrypt private key in place */ | |
213 | zz = enckey->enckey->digest->data; | |
214 | EVP_CIPHER_CTX_init(&ctx); | |
215 | EVP_EncryptInit_ex(&ctx, EVP_rc4(), NULL, key, NULL); | |
216 | EVP_EncryptUpdate(&ctx, zz, &i, zz, pkeylen); | |
217 | EVP_EncryptFinal_ex(&ctx, zz + i, &j); | |
218 | EVP_CIPHER_CTX_cleanup(&ctx); | |
219 | ||
220 | ret = i2d_NETSCAPE_ENCRYPTED_PKEY(enckey, pp); | |
221 | err: | |
222 | NETSCAPE_ENCRYPTED_PKEY_free(enckey); | |
223 | NETSCAPE_PKEY_free(pkey); | |
224 | return (ret); | |
225 | } | |
d3ed8ceb | 226 | |
41a15c4f | 227 | RSA *d2i_Netscape_RSA(RSA **a, const unsigned char **pp, long length, |
40720ce3 MC |
228 | int (*cb) (char *buf, int len, const char *prompt, |
229 | int verify)) | |
d3ed8ceb | 230 | { |
40720ce3 | 231 | return d2i_RSA_NET(a, pp, length, cb, 0); |
d3ed8ceb DSH |
232 | } |
233 | ||
41a15c4f | 234 | RSA *d2i_RSA_NET(RSA **a, const unsigned char **pp, long length, |
40720ce3 MC |
235 | int (*cb) (char *buf, int len, const char *prompt, |
236 | int verify), int sgckey) | |
237 | { | |
238 | RSA *ret = NULL; | |
239 | const unsigned char *p; | |
240 | NETSCAPE_ENCRYPTED_PKEY *enckey = NULL; | |
241 | ||
242 | p = *pp; | |
243 | ||
244 | enckey = d2i_NETSCAPE_ENCRYPTED_PKEY(NULL, &p, length); | |
245 | if (!enckey) { | |
246 | ASN1err(ASN1_F_D2I_RSA_NET, ASN1_R_DECODING_ERROR); | |
247 | return NULL; | |
248 | } | |
249 | ||
250 | if ((enckey->os->length != 11) || (strncmp("private-key", | |
251 | (char *)enckey->os->data, | |
252 | 11) != 0)) { | |
253 | ASN1err(ASN1_F_D2I_RSA_NET, ASN1_R_PRIVATE_KEY_HEADER_MISSING); | |
254 | NETSCAPE_ENCRYPTED_PKEY_free(enckey); | |
255 | return NULL; | |
256 | } | |
257 | if (OBJ_obj2nid(enckey->enckey->algor->algorithm) != NID_rc4) { | |
258 | ASN1err(ASN1_F_D2I_RSA_NET, ASN1_R_UNSUPPORTED_ENCRYPTION_ALGORITHM); | |
259 | goto err; | |
260 | } | |
261 | if (cb == NULL) | |
262 | cb = EVP_read_pw_string; | |
263 | if ((ret = d2i_RSA_NET_2(a, enckey->enckey->digest, cb, sgckey)) == NULL) | |
264 | goto err; | |
265 | ||
266 | *pp = p; | |
267 | ||
268 | err: | |
269 | NETSCAPE_ENCRYPTED_PKEY_free(enckey); | |
270 | return ret; | |
271 | ||
272 | } | |
d3ed8ceb | 273 | |
9d6b1ce6 | 274 | static RSA *d2i_RSA_NET_2(RSA **a, ASN1_OCTET_STRING *os, |
40720ce3 MC |
275 | int (*cb) (char *buf, int len, const char *prompt, |
276 | int verify), int sgckey) | |
277 | { | |
278 | NETSCAPE_PKEY *pkey = NULL; | |
279 | RSA *ret = NULL; | |
280 | int i, j; | |
281 | unsigned char buf[256]; | |
282 | const unsigned char *zz; | |
283 | unsigned char key[EVP_MAX_KEY_LENGTH]; | |
284 | EVP_CIPHER_CTX ctx; | |
285 | ||
286 | i = cb((char *)buf, 256, "Enter Private Key password:", 0); | |
287 | if (i != 0) { | |
288 | ASN1err(ASN1_F_D2I_RSA_NET_2, ASN1_R_BAD_PASSWORD_READ); | |
289 | goto err; | |
290 | } | |
291 | ||
292 | i = strlen((char *)buf); | |
293 | if (sgckey) { | |
294 | EVP_Digest(buf, i, buf, NULL, EVP_md5(), NULL); | |
295 | memcpy(buf + 16, "SGCKEYSALT", 10); | |
296 | i = 26; | |
297 | } | |
298 | ||
299 | EVP_BytesToKey(EVP_rc4(), EVP_md5(), NULL, buf, i, 1, key, NULL); | |
300 | OPENSSL_cleanse(buf, 256); | |
301 | ||
302 | EVP_CIPHER_CTX_init(&ctx); | |
303 | EVP_DecryptInit_ex(&ctx, EVP_rc4(), NULL, key, NULL); | |
304 | EVP_DecryptUpdate(&ctx, os->data, &i, os->data, os->length); | |
305 | EVP_DecryptFinal_ex(&ctx, &(os->data[i]), &j); | |
306 | EVP_CIPHER_CTX_cleanup(&ctx); | |
307 | os->length = i + j; | |
308 | ||
309 | zz = os->data; | |
310 | ||
311 | if ((pkey = d2i_NETSCAPE_PKEY(NULL, &zz, os->length)) == NULL) { | |
312 | ASN1err(ASN1_F_D2I_RSA_NET_2, | |
313 | ASN1_R_UNABLE_TO_DECODE_RSA_PRIVATE_KEY); | |
314 | goto err; | |
315 | } | |
316 | ||
317 | zz = pkey->private_key->data; | |
318 | if ((ret = d2i_RSAPrivateKey(a, &zz, pkey->private_key->length)) == NULL) { | |
319 | ASN1err(ASN1_F_D2I_RSA_NET_2, ASN1_R_UNABLE_TO_DECODE_RSA_KEY); | |
320 | goto err; | |
321 | } | |
322 | err: | |
323 | NETSCAPE_PKEY_free(pkey); | |
324 | return (ret); | |
325 | } | |
326 | ||
327 | # endif /* OPENSSL_NO_RC4 */ | |
328 | ||
329 | #else /* !OPENSSL_NO_RSA */ | |
752d706a BL |
330 | |
331 | # if PEDANTIC | |
40720ce3 | 332 | static void *dummy = &dummy; |
752d706a BL |
333 | # endif |
334 | ||
f5d7a031 | 335 | #endif |