155714Skris/* crypto/asn1/n_pkey.c */
255714Skris/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
355714Skris * All rights reserved.
455714Skris *
555714Skris * This package is an SSL implementation written
655714Skris * by Eric Young (eay@cryptsoft.com).
755714Skris * The implementation was written so as to conform with Netscapes SSL.
8296465Sdelphij *
955714Skris * This library is free for commercial and non-commercial use as long as
1055714Skris * the following conditions are aheared to.  The following conditions
1155714Skris * apply to all code found in this distribution, be it the RC4, RSA,
1255714Skris * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
1355714Skris * included with this distribution is covered by the same copyright terms
1455714Skris * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15296465Sdelphij *
1655714Skris * Copyright remains Eric Young's, and as such any Copyright notices in
1755714Skris * the code are not to be removed.
1855714Skris * If this package is used in a product, Eric Young should be given attribution
1955714Skris * as the author of the parts of the library used.
2055714Skris * This can be in the form of a textual message at program startup or
2155714Skris * in documentation (online or textual) provided with the package.
22296465Sdelphij *
2355714Skris * Redistribution and use in source and binary forms, with or without
2455714Skris * modification, are permitted provided that the following conditions
2555714Skris * are met:
2655714Skris * 1. Redistributions of source code must retain the copyright
2755714Skris *    notice, this list of conditions and the following disclaimer.
2855714Skris * 2. Redistributions in binary form must reproduce the above copyright
2955714Skris *    notice, this list of conditions and the following disclaimer in the
3055714Skris *    documentation and/or other materials provided with the distribution.
3155714Skris * 3. All advertising materials mentioning features or use of this software
3255714Skris *    must display the following acknowledgement:
3355714Skris *    "This product includes cryptographic software written by
3455714Skris *     Eric Young (eay@cryptsoft.com)"
3555714Skris *    The word 'cryptographic' can be left out if the rouines from the library
3655714Skris *    being used are not cryptographic related :-).
37296465Sdelphij * 4. If you include any Windows specific code (or a derivative thereof) from
3855714Skris *    the apps directory (application code) you must include an acknowledgement:
3955714Skris *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40296465Sdelphij *
4155714Skris * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
4255714Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4355714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4455714Skris * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
4555714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4655714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4755714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4855714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4955714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5055714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5155714Skris * SUCH DAMAGE.
52296465Sdelphij *
5355714Skris * The licence and distribution terms for any publically available version or
5455714Skris * derivative of this code cannot be changed.  i.e. this code cannot simply be
5555714Skris * copied and put under another distribution licence
5655714Skris * [including the GNU Public Licence.]
5755714Skris */
5855714Skris
5955714Skris#include <stdio.h>
6055714Skris#include "cryptlib.h"
61160814Ssimon#ifndef OPENSSL_NO_RSA
62296465Sdelphij# include <openssl/rsa.h>
63296465Sdelphij# include <openssl/objects.h>
64296465Sdelphij# include <openssl/asn1t.h>
65296465Sdelphij# include <openssl/asn1_mac.h>
66296465Sdelphij# include <openssl/evp.h>
67296465Sdelphij# include <openssl/x509.h>
6855714Skris
69296465Sdelphij# ifndef OPENSSL_NO_RC4
7055714Skris
71296465Sdelphijtypedef struct netscape_pkey_st {
72296465Sdelphij    long version;
73296465Sdelphij    X509_ALGOR *algor;
74296465Sdelphij    ASN1_OCTET_STRING *private_key;
75296465Sdelphij} NETSCAPE_PKEY;
7655714Skris
77296465Sdelphijtypedef struct netscape_encrypted_pkey_st {
78296465Sdelphij    ASN1_OCTET_STRING *os;
79296465Sdelphij    /*
80296465Sdelphij     * This is the same structure as DigestInfo so use it: although this
81296465Sdelphij     * isn't really anything to do with digests.
82296465Sdelphij     */
83296465Sdelphij    X509_SIG *enckey;
84296465Sdelphij} NETSCAPE_ENCRYPTED_PKEY;
8555714Skris
8655714Skris
87109998SmarkmASN1_BROKEN_SEQUENCE(NETSCAPE_ENCRYPTED_PKEY) = {
88296465Sdelphij        ASN1_SIMPLE(NETSCAPE_ENCRYPTED_PKEY, os, ASN1_OCTET_STRING),
89296465Sdelphij        ASN1_SIMPLE(NETSCAPE_ENCRYPTED_PKEY, enckey, X509_SIG)
90109998Smarkm} ASN1_BROKEN_SEQUENCE_END(NETSCAPE_ENCRYPTED_PKEY)
91109998Smarkm
92109998SmarkmDECLARE_ASN1_FUNCTIONS_const(NETSCAPE_ENCRYPTED_PKEY)
93109998SmarkmDECLARE_ASN1_ENCODE_FUNCTIONS_const(NETSCAPE_ENCRYPTED_PKEY,NETSCAPE_ENCRYPTED_PKEY)
94109998SmarkmIMPLEMENT_ASN1_FUNCTIONS_const(NETSCAPE_ENCRYPTED_PKEY)
95109998Smarkm
96109998SmarkmASN1_SEQUENCE(NETSCAPE_PKEY) = {
97296465Sdelphij        ASN1_SIMPLE(NETSCAPE_PKEY, version, LONG),
98296465Sdelphij        ASN1_SIMPLE(NETSCAPE_PKEY, algor, X509_ALGOR),
99296465Sdelphij        ASN1_SIMPLE(NETSCAPE_PKEY, private_key, ASN1_OCTET_STRING)
100109998Smarkm} ASN1_SEQUENCE_END(NETSCAPE_PKEY)
101109998Smarkm
102109998SmarkmDECLARE_ASN1_FUNCTIONS_const(NETSCAPE_PKEY)
103109998SmarkmDECLARE_ASN1_ENCODE_FUNCTIONS_const(NETSCAPE_PKEY,NETSCAPE_PKEY)
104109998SmarkmIMPLEMENT_ASN1_FUNCTIONS_const(NETSCAPE_PKEY)
105109998Smarkm
106109998Smarkmstatic RSA *d2i_RSA_NET_2(RSA **a, ASN1_OCTET_STRING *os,
107296465Sdelphij                          int (*cb) (char *buf, int len, const char *prompt,
108296465Sdelphij                                     int verify), int sgckey);
109109998Smarkm
110160814Ssimonint i2d_Netscape_RSA(const RSA *a, unsigned char **pp,
111296465Sdelphij                     int (*cb) (char *buf, int len, const char *prompt,
112296465Sdelphij                                int verify))
11368651Skris{
114296465Sdelphij    return i2d_RSA_NET(a, pp, cb, 0);
11568651Skris}
11668651Skris
117160814Ssimonint i2d_RSA_NET(const RSA *a, unsigned char **pp,
118296465Sdelphij                int (*cb) (char *buf, int len, const char *prompt,
119296465Sdelphij                           int verify), int sgckey)
120296465Sdelphij{
121296465Sdelphij    int i, j, ret = 0;
122296465Sdelphij    int rsalen, pkeylen, olen;
123296465Sdelphij    NETSCAPE_PKEY *pkey = NULL;
124296465Sdelphij    NETSCAPE_ENCRYPTED_PKEY *enckey = NULL;
125296465Sdelphij    unsigned char buf[256], *zz;
126296465Sdelphij    unsigned char key[EVP_MAX_KEY_LENGTH];
127296465Sdelphij    EVP_CIPHER_CTX ctx;
12855714Skris
129296465Sdelphij    if (a == NULL)
130296465Sdelphij        return (0);
13155714Skris
132296465Sdelphij    if ((pkey = NETSCAPE_PKEY_new()) == NULL)
133296465Sdelphij        goto err;
134296465Sdelphij    if ((enckey = NETSCAPE_ENCRYPTED_PKEY_new()) == NULL)
135296465Sdelphij        goto err;
136296465Sdelphij    pkey->version = 0;
13755714Skris
138296465Sdelphij    pkey->algor->algorithm = OBJ_nid2obj(NID_rsaEncryption);
139296465Sdelphij    if ((pkey->algor->parameter = ASN1_TYPE_new()) == NULL)
140296465Sdelphij        goto err;
141296465Sdelphij    pkey->algor->parameter->type = V_ASN1_NULL;
14255714Skris
143296465Sdelphij    rsalen = i2d_RSAPrivateKey(a, NULL);
14455714Skris
145296465Sdelphij    /*
146296465Sdelphij     * Fake some octet strings just for the initial length calculation.
147296465Sdelphij     */
14855714Skris
149296465Sdelphij    pkey->private_key->length = rsalen;
15055714Skris
151296465Sdelphij    pkeylen = i2d_NETSCAPE_PKEY(pkey, NULL);
15255714Skris
153296465Sdelphij    enckey->enckey->digest->length = pkeylen;
15455714Skris
155296465Sdelphij    enckey->os->length = 11;    /* "private-key" */
15655714Skris
157296465Sdelphij    enckey->enckey->algor->algorithm = OBJ_nid2obj(NID_rc4);
158296465Sdelphij    if ((enckey->enckey->algor->parameter = ASN1_TYPE_new()) == NULL)
159296465Sdelphij        goto err;
160296465Sdelphij    enckey->enckey->algor->parameter->type = V_ASN1_NULL;
161109998Smarkm
162296465Sdelphij    if (pp == NULL) {
163296465Sdelphij        olen = i2d_NETSCAPE_ENCRYPTED_PKEY(enckey, NULL);
164296465Sdelphij        NETSCAPE_PKEY_free(pkey);
165296465Sdelphij        NETSCAPE_ENCRYPTED_PKEY_free(enckey);
166296465Sdelphij        return olen;
167296465Sdelphij    }
16855714Skris
169296465Sdelphij    /* Since its RC4 encrypted length is actual length */
170296465Sdelphij    if ((zz = (unsigned char *)OPENSSL_malloc(rsalen)) == NULL) {
171296465Sdelphij        ASN1err(ASN1_F_I2D_RSA_NET, ERR_R_MALLOC_FAILURE);
172296465Sdelphij        goto err;
173296465Sdelphij    }
174109998Smarkm
175296465Sdelphij    pkey->private_key->data = zz;
176296465Sdelphij    /* Write out private key encoding */
177296465Sdelphij    i2d_RSAPrivateKey(a, &zz);
178109998Smarkm
179296465Sdelphij    if ((zz = OPENSSL_malloc(pkeylen)) == NULL) {
180296465Sdelphij        ASN1err(ASN1_F_I2D_RSA_NET, ERR_R_MALLOC_FAILURE);
181296465Sdelphij        goto err;
182296465Sdelphij    }
18355714Skris
184296465Sdelphij    if (!ASN1_STRING_set(enckey->os, "private-key", -1)) {
185296465Sdelphij        ASN1err(ASN1_F_I2D_RSA_NET, ERR_R_MALLOC_FAILURE);
186296465Sdelphij        goto err;
187296465Sdelphij    }
188296465Sdelphij    enckey->enckey->digest->data = zz;
189296465Sdelphij    i2d_NETSCAPE_PKEY(pkey, &zz);
190109998Smarkm
191296465Sdelphij    /* Wipe the private key encoding */
192296465Sdelphij    OPENSSL_cleanse(pkey->private_key->data, rsalen);
193109998Smarkm
194296465Sdelphij    if (cb == NULL)
195296465Sdelphij        cb = EVP_read_pw_string;
196296465Sdelphij    i = cb((char *)buf, 256, "Enter Private Key password:", 1);
197296465Sdelphij    if (i != 0) {
198296465Sdelphij        ASN1err(ASN1_F_I2D_RSA_NET, ASN1_R_BAD_PASSWORD_READ);
199296465Sdelphij        goto err;
200296465Sdelphij    }
201296465Sdelphij    i = strlen((char *)buf);
202296465Sdelphij    /* If the key is used for SGC the algorithm is modified a little. */
203296465Sdelphij    if (sgckey) {
204296465Sdelphij        EVP_Digest(buf, i, buf, NULL, EVP_md5(), NULL);
205296465Sdelphij        memcpy(buf + 16, "SGCKEYSALT", 10);
206296465Sdelphij        i = 26;
207296465Sdelphij    }
208109998Smarkm
209296465Sdelphij    EVP_BytesToKey(EVP_rc4(), EVP_md5(), NULL, buf, i, 1, key, NULL);
210296465Sdelphij    OPENSSL_cleanse(buf, 256);
21155714Skris
212296465Sdelphij    /* Encrypt private key in place */
213296465Sdelphij    zz = enckey->enckey->digest->data;
214296465Sdelphij    EVP_CIPHER_CTX_init(&ctx);
215296465Sdelphij    EVP_EncryptInit_ex(&ctx, EVP_rc4(), NULL, key, NULL);
216296465Sdelphij    EVP_EncryptUpdate(&ctx, zz, &i, zz, pkeylen);
217296465Sdelphij    EVP_EncryptFinal_ex(&ctx, zz + i, &j);
218296465Sdelphij    EVP_CIPHER_CTX_cleanup(&ctx);
21955714Skris
220296465Sdelphij    ret = i2d_NETSCAPE_ENCRYPTED_PKEY(enckey, pp);
221296465Sdelphij err:
222296465Sdelphij    NETSCAPE_ENCRYPTED_PKEY_free(enckey);
223296465Sdelphij    NETSCAPE_PKEY_free(pkey);
224296465Sdelphij    return (ret);
225296465Sdelphij}
22655714Skris
227160814SsimonRSA *d2i_Netscape_RSA(RSA **a, const unsigned char **pp, long length,
228296465Sdelphij                      int (*cb) (char *buf, int len, const char *prompt,
229296465Sdelphij                                 int verify))
23068651Skris{
231296465Sdelphij    return d2i_RSA_NET(a, pp, length, cb, 0);
23268651Skris}
23368651Skris
234160814SsimonRSA *d2i_RSA_NET(RSA **a, const unsigned char **pp, long length,
235296465Sdelphij                 int (*cb) (char *buf, int len, const char *prompt,
236296465Sdelphij                            int verify), int sgckey)
237296465Sdelphij{
238296465Sdelphij    RSA *ret = NULL;
239296465Sdelphij    const unsigned char *p;
240296465Sdelphij    NETSCAPE_ENCRYPTED_PKEY *enckey = NULL;
24155714Skris
242296465Sdelphij    p = *pp;
24355714Skris
244296465Sdelphij    enckey = d2i_NETSCAPE_ENCRYPTED_PKEY(NULL, &p, length);
245296465Sdelphij    if (!enckey) {
246296465Sdelphij        ASN1err(ASN1_F_D2I_RSA_NET, ASN1_R_DECODING_ERROR);
247296465Sdelphij        return NULL;
248296465Sdelphij    }
249109998Smarkm
250296465Sdelphij    if ((enckey->os->length != 11) || (strncmp("private-key",
251296465Sdelphij                                               (char *)enckey->os->data,
252296465Sdelphij                                               11) != 0)) {
253296465Sdelphij        ASN1err(ASN1_F_D2I_RSA_NET, ASN1_R_PRIVATE_KEY_HEADER_MISSING);
254296465Sdelphij        NETSCAPE_ENCRYPTED_PKEY_free(enckey);
255296465Sdelphij        return NULL;
256296465Sdelphij    }
257296465Sdelphij    if (OBJ_obj2nid(enckey->enckey->algor->algorithm) != NID_rc4) {
258296465Sdelphij        ASN1err(ASN1_F_D2I_RSA_NET, ASN1_R_UNSUPPORTED_ENCRYPTION_ALGORITHM);
259296465Sdelphij        goto err;
260296465Sdelphij    }
261296465Sdelphij    if (cb == NULL)
262296465Sdelphij        cb = EVP_read_pw_string;
263296465Sdelphij    if ((ret = d2i_RSA_NET_2(a, enckey->enckey->digest, cb, sgckey)) == NULL)
264296465Sdelphij        goto err;
26555714Skris
266296465Sdelphij    *pp = p;
267109998Smarkm
268296465Sdelphij err:
269296465Sdelphij    NETSCAPE_ENCRYPTED_PKEY_free(enckey);
270296465Sdelphij    return ret;
271109998Smarkm
272296465Sdelphij}
27355714Skris
274109998Smarkmstatic RSA *d2i_RSA_NET_2(RSA **a, ASN1_OCTET_STRING *os,
275296465Sdelphij                          int (*cb) (char *buf, int len, const char *prompt,
276296465Sdelphij                                     int verify), int sgckey)
277296465Sdelphij{
278296465Sdelphij    NETSCAPE_PKEY *pkey = NULL;
279296465Sdelphij    RSA *ret = NULL;
280296465Sdelphij    int i, j;
281296465Sdelphij    unsigned char buf[256];
282296465Sdelphij    const unsigned char *zz;
283296465Sdelphij    unsigned char key[EVP_MAX_KEY_LENGTH];
284296465Sdelphij    EVP_CIPHER_CTX ctx;
28555714Skris
286296465Sdelphij    i = cb((char *)buf, 256, "Enter Private Key password:", 0);
287296465Sdelphij    if (i != 0) {
288296465Sdelphij        ASN1err(ASN1_F_D2I_RSA_NET_2, ASN1_R_BAD_PASSWORD_READ);
289296465Sdelphij        goto err;
290296465Sdelphij    }
29155714Skris
292296465Sdelphij    i = strlen((char *)buf);
293296465Sdelphij    if (sgckey) {
294296465Sdelphij        EVP_Digest(buf, i, buf, NULL, EVP_md5(), NULL);
295296465Sdelphij        memcpy(buf + 16, "SGCKEYSALT", 10);
296296465Sdelphij        i = 26;
297296465Sdelphij    }
29855714Skris
299296465Sdelphij    EVP_BytesToKey(EVP_rc4(), EVP_md5(), NULL, buf, i, 1, key, NULL);
300296465Sdelphij    OPENSSL_cleanse(buf, 256);
30155714Skris
302296465Sdelphij    EVP_CIPHER_CTX_init(&ctx);
303296465Sdelphij    EVP_DecryptInit_ex(&ctx, EVP_rc4(), NULL, key, NULL);
304296465Sdelphij    EVP_DecryptUpdate(&ctx, os->data, &i, os->data, os->length);
305296465Sdelphij    EVP_DecryptFinal_ex(&ctx, &(os->data[i]), &j);
306296465Sdelphij    EVP_CIPHER_CTX_cleanup(&ctx);
307296465Sdelphij    os->length = i + j;
30855714Skris
309296465Sdelphij    zz = os->data;
31055714Skris
311296465Sdelphij    if ((pkey = d2i_NETSCAPE_PKEY(NULL, &zz, os->length)) == NULL) {
312296465Sdelphij        ASN1err(ASN1_F_D2I_RSA_NET_2,
313296465Sdelphij                ASN1_R_UNABLE_TO_DECODE_RSA_PRIVATE_KEY);
314296465Sdelphij        goto err;
315296465Sdelphij    }
31655714Skris
317296465Sdelphij    zz = pkey->private_key->data;
318296465Sdelphij    if ((ret = d2i_RSAPrivateKey(a, &zz, pkey->private_key->length)) == NULL) {
319296465Sdelphij        ASN1err(ASN1_F_D2I_RSA_NET_2, ASN1_R_UNABLE_TO_DECODE_RSA_KEY);
320296465Sdelphij        goto err;
321296465Sdelphij    }
322296465Sdelphij err:
323296465Sdelphij    NETSCAPE_PKEY_free(pkey);
324296465Sdelphij    return (ret);
325296465Sdelphij}
32655714Skris
327296465Sdelphij# endif                         /* OPENSSL_NO_RC4 */
328296465Sdelphij
329296465Sdelphij#else                           /* !OPENSSL_NO_RSA */
330296465Sdelphij
33159191Skris# if PEDANTIC
332296465Sdelphijstatic void *dummy = &dummy;
33359191Skris# endif
33459191Skris
33555714Skris#endif
336