|
1 /* crypto/asn1/n_pkey.c */ |
|
2 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) |
|
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. |
|
8 * |
|
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). |
|
15 * |
|
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. |
|
22 * |
|
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 :-). |
|
37 * 4. If you include any Windows specific code (or a derivative thereof) from |
|
38 * the apps directory (application code) you must include an acknowledgement: |
|
39 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" |
|
40 * |
|
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. |
|
52 * |
|
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 © Portions copyright (c) 2006 Nokia Corporation. All rights reserved. |
|
60 */ |
|
61 |
|
62 #include <stdio.h> |
|
63 #include "cryptlib.h" |
|
64 #ifndef OPENSSL_NO_RSA |
|
65 #include <openssl/rsa.h> |
|
66 #include <openssl/objects.h> |
|
67 #include <openssl/asn1t.h> |
|
68 #include <openssl/asn1_mac.h> |
|
69 #include <openssl/evp.h> |
|
70 #include <openssl/x509.h> |
|
71 |
|
72 |
|
73 #ifndef OPENSSL_NO_RC4 |
|
74 |
|
75 typedef struct netscape_pkey_st |
|
76 { |
|
77 long version; |
|
78 X509_ALGOR *algor; |
|
79 ASN1_OCTET_STRING *private_key; |
|
80 } NETSCAPE_PKEY; |
|
81 |
|
82 typedef struct netscape_encrypted_pkey_st |
|
83 { |
|
84 ASN1_OCTET_STRING *os; |
|
85 /* This is the same structure as DigestInfo so use it: |
|
86 * although this isn't really anything to do with |
|
87 * digests. |
|
88 */ |
|
89 X509_SIG *enckey; |
|
90 } NETSCAPE_ENCRYPTED_PKEY; |
|
91 |
|
92 |
|
93 ASN1_BROKEN_SEQUENCE(NETSCAPE_ENCRYPTED_PKEY) = { |
|
94 ASN1_SIMPLE(NETSCAPE_ENCRYPTED_PKEY, os, ASN1_OCTET_STRING), |
|
95 ASN1_SIMPLE(NETSCAPE_ENCRYPTED_PKEY, enckey, X509_SIG) |
|
96 } ASN1_BROKEN_SEQUENCE_END(NETSCAPE_ENCRYPTED_PKEY) |
|
97 |
|
98 DECLARE_ASN1_FUNCTIONS_const(NETSCAPE_ENCRYPTED_PKEY) |
|
99 DECLARE_ASN1_ENCODE_FUNCTIONS_const(NETSCAPE_ENCRYPTED_PKEY,NETSCAPE_ENCRYPTED_PKEY) |
|
100 IMPLEMENT_ASN1_FUNCTIONS_const(NETSCAPE_ENCRYPTED_PKEY) |
|
101 |
|
102 ASN1_SEQUENCE(NETSCAPE_PKEY) = { |
|
103 ASN1_SIMPLE(NETSCAPE_PKEY, version, LONG), |
|
104 ASN1_SIMPLE(NETSCAPE_PKEY, algor, X509_ALGOR), |
|
105 ASN1_SIMPLE(NETSCAPE_PKEY, private_key, ASN1_OCTET_STRING) |
|
106 } ASN1_SEQUENCE_END(NETSCAPE_PKEY) |
|
107 |
|
108 DECLARE_ASN1_FUNCTIONS_const(NETSCAPE_PKEY) |
|
109 DECLARE_ASN1_ENCODE_FUNCTIONS_const(NETSCAPE_PKEY,NETSCAPE_PKEY) |
|
110 IMPLEMENT_ASN1_FUNCTIONS_const(NETSCAPE_PKEY) |
|
111 |
|
112 static RSA *d2i_RSA_NET_2(RSA **a, ASN1_OCTET_STRING *os, |
|
113 int (*cb)(char *buf, int len, const char *prompt, |
|
114 int verify), |
|
115 int sgckey); |
|
116 |
|
117 EXPORT_C int i2d_Netscape_RSA(const RSA *a, unsigned char **pp, |
|
118 int (*cb)(char *buf, int len, const char *prompt, |
|
119 int verify)) |
|
120 { |
|
121 return i2d_RSA_NET(a, pp, cb, 0); |
|
122 } |
|
123 |
|
124 EXPORT_C int i2d_RSA_NET(const RSA *a, unsigned char **pp, |
|
125 int (*cb)(char *buf, int len, const char *prompt, int verify), |
|
126 int sgckey) |
|
127 { |
|
128 int i, j, ret = 0; |
|
129 int rsalen, pkeylen, olen; |
|
130 NETSCAPE_PKEY *pkey = NULL; |
|
131 NETSCAPE_ENCRYPTED_PKEY *enckey = NULL; |
|
132 unsigned char buf[256],*zz; |
|
133 unsigned char key[EVP_MAX_KEY_LENGTH]; |
|
134 EVP_CIPHER_CTX ctx; |
|
135 |
|
136 if (a == NULL) return(0); |
|
137 |
|
138 if ((pkey=NETSCAPE_PKEY_new()) == NULL) goto err; |
|
139 if ((enckey=NETSCAPE_ENCRYPTED_PKEY_new()) == NULL) goto err; |
|
140 pkey->version = 0; |
|
141 |
|
142 pkey->algor->algorithm=OBJ_nid2obj(NID_rsaEncryption); |
|
143 if ((pkey->algor->parameter=ASN1_TYPE_new()) == NULL) goto err; |
|
144 pkey->algor->parameter->type=V_ASN1_NULL; |
|
145 |
|
146 rsalen = i2d_RSAPrivateKey(a, NULL); |
|
147 |
|
148 /* Fake some octet strings just for the initial length |
|
149 * calculation. |
|
150 */ |
|
151 |
|
152 pkey->private_key->length=rsalen; |
|
153 |
|
154 pkeylen=i2d_NETSCAPE_PKEY(pkey,NULL); |
|
155 |
|
156 enckey->enckey->digest->length = pkeylen; |
|
157 |
|
158 enckey->os->length = 11; /* "private-key" */ |
|
159 |
|
160 enckey->enckey->algor->algorithm=OBJ_nid2obj(NID_rc4); |
|
161 if ((enckey->enckey->algor->parameter=ASN1_TYPE_new()) == NULL) goto err; |
|
162 enckey->enckey->algor->parameter->type=V_ASN1_NULL; |
|
163 |
|
164 if (pp == NULL) |
|
165 { |
|
166 olen = i2d_NETSCAPE_ENCRYPTED_PKEY(enckey, NULL); |
|
167 NETSCAPE_PKEY_free(pkey); |
|
168 NETSCAPE_ENCRYPTED_PKEY_free(enckey); |
|
169 return olen; |
|
170 } |
|
171 |
|
172 |
|
173 /* Since its RC4 encrypted length is actual length */ |
|
174 if ((zz=(unsigned char *)OPENSSL_malloc(rsalen)) == NULL) |
|
175 { |
|
176 ASN1err(ASN1_F_I2D_RSA_NET,ERR_R_MALLOC_FAILURE); |
|
177 goto err; |
|
178 } |
|
179 |
|
180 pkey->private_key->data = zz; |
|
181 /* Write out private key encoding */ |
|
182 i2d_RSAPrivateKey(a,&zz); |
|
183 |
|
184 if ((zz=OPENSSL_malloc(pkeylen)) == NULL) |
|
185 { |
|
186 ASN1err(ASN1_F_I2D_RSA_NET,ERR_R_MALLOC_FAILURE); |
|
187 goto err; |
|
188 } |
|
189 |
|
190 if (!ASN1_STRING_set(enckey->os, "private-key", -1)) |
|
191 { |
|
192 ASN1err(ASN1_F_I2D_RSA_NET,ERR_R_MALLOC_FAILURE); |
|
193 goto err; |
|
194 } |
|
195 enckey->enckey->digest->data = zz; |
|
196 i2d_NETSCAPE_PKEY(pkey,&zz); |
|
197 |
|
198 /* Wipe the private key encoding */ |
|
199 OPENSSL_cleanse(pkey->private_key->data, rsalen); |
|
200 |
|
201 if (cb == NULL) |
|
202 cb=EVP_read_pw_string; |
|
203 i=cb((char *)buf,256,"Enter Private Key password:",1); |
|
204 if (i != 0) |
|
205 { |
|
206 ASN1err(ASN1_F_I2D_RSA_NET,ASN1_R_BAD_PASSWORD_READ); |
|
207 goto err; |
|
208 } |
|
209 i = strlen((char *)buf); |
|
210 /* If the key is used for SGC the algorithm is modified a little. */ |
|
211 if(sgckey) { |
|
212 EVP_Digest(buf, i, buf, NULL, EVP_md5(), NULL); |
|
213 memcpy(buf + 16, "SGCKEYSALT", 10); |
|
214 i = 26; |
|
215 } |
|
216 |
|
217 EVP_BytesToKey(EVP_rc4(),EVP_md5(),NULL,buf,i,1,key,NULL); |
|
218 OPENSSL_cleanse(buf,256); |
|
219 |
|
220 /* Encrypt private key in place */ |
|
221 zz = enckey->enckey->digest->data; |
|
222 EVP_CIPHER_CTX_init(&ctx); |
|
223 EVP_EncryptInit_ex(&ctx,EVP_rc4(),NULL,key,NULL); |
|
224 EVP_EncryptUpdate(&ctx,zz,&i,zz,pkeylen); |
|
225 EVP_EncryptFinal_ex(&ctx,zz + i,&j); |
|
226 EVP_CIPHER_CTX_cleanup(&ctx); |
|
227 |
|
228 ret = i2d_NETSCAPE_ENCRYPTED_PKEY(enckey, pp); |
|
229 err: |
|
230 NETSCAPE_ENCRYPTED_PKEY_free(enckey); |
|
231 NETSCAPE_PKEY_free(pkey); |
|
232 return(ret); |
|
233 } |
|
234 |
|
235 |
|
236 EXPORT_C RSA *d2i_Netscape_RSA(RSA **a, const unsigned char **pp, long length, |
|
237 int (*cb)(char *buf, int len, const char *prompt, |
|
238 int verify)) |
|
239 { |
|
240 return d2i_RSA_NET(a, pp, length, cb, 0); |
|
241 } |
|
242 |
|
243 EXPORT_C RSA *d2i_RSA_NET(RSA **a, const unsigned char **pp, long length, |
|
244 int (*cb)(char *buf, int len, const char *prompt, int verify), |
|
245 int sgckey) |
|
246 { |
|
247 RSA *ret=NULL; |
|
248 const unsigned char *p, *kp; |
|
249 NETSCAPE_ENCRYPTED_PKEY *enckey = NULL; |
|
250 |
|
251 p = *pp; |
|
252 |
|
253 enckey = d2i_NETSCAPE_ENCRYPTED_PKEY(NULL, &p, length); |
|
254 if(!enckey) { |
|
255 ASN1err(ASN1_F_D2I_RSA_NET,ASN1_R_DECODING_ERROR); |
|
256 return NULL; |
|
257 } |
|
258 |
|
259 if ((enckey->os->length != 11) || (strncmp("private-key", |
|
260 (char *)enckey->os->data,11) != 0)) |
|
261 { |
|
262 ASN1err(ASN1_F_D2I_RSA_NET,ASN1_R_PRIVATE_KEY_HEADER_MISSING); |
|
263 NETSCAPE_ENCRYPTED_PKEY_free(enckey); |
|
264 return NULL; |
|
265 } |
|
266 if (OBJ_obj2nid(enckey->enckey->algor->algorithm) != NID_rc4) |
|
267 { |
|
268 ASN1err(ASN1_F_D2I_RSA_NET,ASN1_R_UNSUPPORTED_ENCRYPTION_ALGORITHM); |
|
269 goto err; |
|
270 } |
|
271 kp = enckey->enckey->digest->data; |
|
272 if (cb == NULL) |
|
273 cb=EVP_read_pw_string; |
|
274 if ((ret=d2i_RSA_NET_2(a, enckey->enckey->digest,cb, sgckey)) == NULL) goto err; |
|
275 |
|
276 *pp = p; |
|
277 |
|
278 err: |
|
279 NETSCAPE_ENCRYPTED_PKEY_free(enckey); |
|
280 return ret; |
|
281 |
|
282 } |
|
283 |
|
284 static RSA *d2i_RSA_NET_2(RSA **a, ASN1_OCTET_STRING *os, |
|
285 int (*cb)(char *buf, int len, const char *prompt, |
|
286 int verify), int sgckey) |
|
287 { |
|
288 NETSCAPE_PKEY *pkey=NULL; |
|
289 RSA *ret=NULL; |
|
290 int i,j; |
|
291 unsigned char buf[256]; |
|
292 const unsigned char *zz; |
|
293 unsigned char key[EVP_MAX_KEY_LENGTH]; |
|
294 EVP_CIPHER_CTX ctx; |
|
295 |
|
296 i=cb((char *)buf,256,"Enter Private Key password:",0); |
|
297 if (i != 0) |
|
298 { |
|
299 ASN1err(ASN1_F_D2I_RSA_NET_2,ASN1_R_BAD_PASSWORD_READ); |
|
300 goto err; |
|
301 } |
|
302 |
|
303 i = strlen((char *)buf); |
|
304 if(sgckey){ |
|
305 EVP_Digest(buf, i, buf, NULL, EVP_md5(), NULL); |
|
306 memcpy(buf + 16, "SGCKEYSALT", 10); |
|
307 i = 26; |
|
308 } |
|
309 |
|
310 EVP_BytesToKey(EVP_rc4(),EVP_md5(),NULL,buf,i,1,key,NULL); |
|
311 OPENSSL_cleanse(buf,256); |
|
312 |
|
313 EVP_CIPHER_CTX_init(&ctx); |
|
314 EVP_DecryptInit_ex(&ctx,EVP_rc4(),NULL, key,NULL); |
|
315 EVP_DecryptUpdate(&ctx,os->data,&i,os->data,os->length); |
|
316 EVP_DecryptFinal_ex(&ctx,&(os->data[i]),&j); |
|
317 EVP_CIPHER_CTX_cleanup(&ctx); |
|
318 os->length=i+j; |
|
319 |
|
320 zz=os->data; |
|
321 |
|
322 if ((pkey=d2i_NETSCAPE_PKEY(NULL,&zz,os->length)) == NULL) |
|
323 { |
|
324 ASN1err(ASN1_F_D2I_RSA_NET_2,ASN1_R_UNABLE_TO_DECODE_RSA_PRIVATE_KEY); |
|
325 goto err; |
|
326 } |
|
327 |
|
328 zz=pkey->private_key->data; |
|
329 if ((ret=d2i_RSAPrivateKey(a,&zz,pkey->private_key->length)) == NULL) |
|
330 { |
|
331 ASN1err(ASN1_F_D2I_RSA_NET_2,ASN1_R_UNABLE_TO_DECODE_RSA_KEY); |
|
332 goto err; |
|
333 } |
|
334 |
|
335 err: |
|
336 NETSCAPE_PKEY_free(pkey); |
|
337 return(ret); |
|
338 } |
|
339 |
|
340 #endif /* OPENSSL_NO_RC4 */ |
|
341 |
|
342 #else /* !OPENSSL_NO_RSA */ |
|
343 |
|
344 # if PEDANTIC |
|
345 static void *dummy=&dummy; |
|
346 # endif |
|
347 |
|
348 #endif |