1109998Smarkm/* crypto/pem/pem_pkey.c */
2109998Smarkm/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3109998Smarkm * All rights reserved.
4109998Smarkm *
5109998Smarkm * This package is an SSL implementation written
6109998Smarkm * by Eric Young (eay@cryptsoft.com).
7109998Smarkm * The implementation was written so as to conform with Netscapes SSL.
8280297Sjkim *
9109998Smarkm * This library is free for commercial and non-commercial use as long as
10109998Smarkm * the following conditions are aheared to.  The following conditions
11109998Smarkm * apply to all code found in this distribution, be it the RC4, RSA,
12109998Smarkm * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
13109998Smarkm * included with this distribution is covered by the same copyright terms
14109998Smarkm * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15280297Sjkim *
16109998Smarkm * Copyright remains Eric Young's, and as such any Copyright notices in
17109998Smarkm * the code are not to be removed.
18109998Smarkm * If this package is used in a product, Eric Young should be given attribution
19109998Smarkm * as the author of the parts of the library used.
20109998Smarkm * This can be in the form of a textual message at program startup or
21109998Smarkm * in documentation (online or textual) provided with the package.
22280297Sjkim *
23109998Smarkm * Redistribution and use in source and binary forms, with or without
24109998Smarkm * modification, are permitted provided that the following conditions
25109998Smarkm * are met:
26109998Smarkm * 1. Redistributions of source code must retain the copyright
27109998Smarkm *    notice, this list of conditions and the following disclaimer.
28109998Smarkm * 2. Redistributions in binary form must reproduce the above copyright
29109998Smarkm *    notice, this list of conditions and the following disclaimer in the
30109998Smarkm *    documentation and/or other materials provided with the distribution.
31109998Smarkm * 3. All advertising materials mentioning features or use of this software
32109998Smarkm *    must display the following acknowledgement:
33109998Smarkm *    "This product includes cryptographic software written by
34109998Smarkm *     Eric Young (eay@cryptsoft.com)"
35109998Smarkm *    The word 'cryptographic' can be left out if the rouines from the library
36109998Smarkm *    being used are not cryptographic related :-).
37280297Sjkim * 4. If you include any Windows specific code (or a derivative thereof) from
38109998Smarkm *    the apps directory (application code) you must include an acknowledgement:
39109998Smarkm *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40280297Sjkim *
41109998Smarkm * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42109998Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43109998Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44109998Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45109998Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46109998Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47109998Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48109998Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49109998Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50109998Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51109998Smarkm * SUCH DAMAGE.
52280297Sjkim *
53109998Smarkm * The licence and distribution terms for any publically available version or
54109998Smarkm * derivative of this code cannot be changed.  i.e. this code cannot simply be
55109998Smarkm * copied and put under another distribution licence
56109998Smarkm * [including the GNU Public Licence.]
57109998Smarkm */
58109998Smarkm
59109998Smarkm#include <stdio.h>
60109998Smarkm#include "cryptlib.h"
61109998Smarkm#include <openssl/buffer.h>
62109998Smarkm#include <openssl/objects.h>
63109998Smarkm#include <openssl/evp.h>
64109998Smarkm#include <openssl/rand.h>
65109998Smarkm#include <openssl/x509.h>
66109998Smarkm#include <openssl/pkcs12.h>
67109998Smarkm#include <openssl/pem.h>
68109998Smarkm
69109998Smarkmstatic int do_pk8pkey(BIO *bp, EVP_PKEY *x, int isder,
70280297Sjkim                      int nid, const EVP_CIPHER *enc,
71280297Sjkim                      char *kstr, int klen, pem_password_cb *cb, void *u);
72109998Smarkmstatic int do_pk8pkey_fp(FILE *bp, EVP_PKEY *x, int isder,
73280297Sjkim                         int nid, const EVP_CIPHER *enc,
74280297Sjkim                         char *kstr, int klen, pem_password_cb *cb, void *u);
75109998Smarkm
76280297Sjkim/*
77280297Sjkim * These functions write a private key in PKCS#8 format: it is a "drop in"
78109998Smarkm * replacement for PEM_write_bio_PrivateKey() and friends. As usual if 'enc'
79109998Smarkm * is NULL then it uses the unencrypted private key form. The 'nid' versions
80109998Smarkm * uses PKCS#5 v1.5 PBE algorithms whereas the others use PKCS#5 v2.0.
81109998Smarkm */
82109998Smarkm
83109998Smarkmint PEM_write_bio_PKCS8PrivateKey_nid(BIO *bp, EVP_PKEY *x, int nid,
84280297Sjkim                                      char *kstr, int klen,
85280297Sjkim                                      pem_password_cb *cb, void *u)
86109998Smarkm{
87280297Sjkim    return do_pk8pkey(bp, x, 0, nid, NULL, kstr, klen, cb, u);
88109998Smarkm}
89109998Smarkm
90109998Smarkmint PEM_write_bio_PKCS8PrivateKey(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc,
91280297Sjkim                                  char *kstr, int klen,
92280297Sjkim                                  pem_password_cb *cb, void *u)
93109998Smarkm{
94280297Sjkim    return do_pk8pkey(bp, x, 0, -1, enc, kstr, klen, cb, u);
95109998Smarkm}
96109998Smarkm
97109998Smarkmint i2d_PKCS8PrivateKey_bio(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc,
98280297Sjkim                            char *kstr, int klen,
99280297Sjkim                            pem_password_cb *cb, void *u)
100109998Smarkm{
101280297Sjkim    return do_pk8pkey(bp, x, 1, -1, enc, kstr, klen, cb, u);
102109998Smarkm}
103109998Smarkm
104109998Smarkmint i2d_PKCS8PrivateKey_nid_bio(BIO *bp, EVP_PKEY *x, int nid,
105280297Sjkim                                char *kstr, int klen,
106280297Sjkim                                pem_password_cb *cb, void *u)
107109998Smarkm{
108280297Sjkim    return do_pk8pkey(bp, x, 1, nid, NULL, kstr, klen, cb, u);
109109998Smarkm}
110109998Smarkm
111280297Sjkimstatic int do_pk8pkey(BIO *bp, EVP_PKEY *x, int isder, int nid,
112280297Sjkim                      const EVP_CIPHER *enc, char *kstr, int klen,
113280297Sjkim                      pem_password_cb *cb, void *u)
114109998Smarkm{
115280297Sjkim    X509_SIG *p8;
116280297Sjkim    PKCS8_PRIV_KEY_INFO *p8inf;
117280297Sjkim    char buf[PEM_BUFSIZE];
118280297Sjkim    int ret;
119280297Sjkim    if (!(p8inf = EVP_PKEY2PKCS8(x))) {
120280297Sjkim        PEMerr(PEM_F_DO_PK8PKEY, PEM_R_ERROR_CONVERTING_PRIVATE_KEY);
121280297Sjkim        return 0;
122280297Sjkim    }
123280297Sjkim    if (enc || (nid != -1)) {
124280297Sjkim        if (!kstr) {
125280297Sjkim            if (!cb)
126280297Sjkim                klen = PEM_def_callback(buf, PEM_BUFSIZE, 1, u);
127280297Sjkim            else
128280297Sjkim                klen = cb(buf, PEM_BUFSIZE, 1, u);
129280297Sjkim            if (klen <= 0) {
130280297Sjkim                PEMerr(PEM_F_DO_PK8PKEY, PEM_R_READ_KEY);
131280297Sjkim                PKCS8_PRIV_KEY_INFO_free(p8inf);
132280297Sjkim                return 0;
133280297Sjkim            }
134280297Sjkim
135280297Sjkim            kstr = buf;
136280297Sjkim        }
137280297Sjkim        p8 = PKCS8_encrypt(nid, enc, kstr, klen, NULL, 0, 0, p8inf);
138280297Sjkim        if (kstr == buf)
139280297Sjkim            OPENSSL_cleanse(buf, klen);
140280297Sjkim        PKCS8_PRIV_KEY_INFO_free(p8inf);
141284283Sjkim        if (p8 == NULL)
142284283Sjkim            return 0;
143280297Sjkim        if (isder)
144280297Sjkim            ret = i2d_PKCS8_bio(bp, p8);
145280297Sjkim        else
146280297Sjkim            ret = PEM_write_bio_PKCS8(bp, p8);
147280297Sjkim        X509_SIG_free(p8);
148280297Sjkim        return ret;
149280297Sjkim    } else {
150280297Sjkim        if (isder)
151280297Sjkim            ret = i2d_PKCS8_PRIV_KEY_INFO_bio(bp, p8inf);
152280297Sjkim        else
153280297Sjkim            ret = PEM_write_bio_PKCS8_PRIV_KEY_INFO(bp, p8inf);
154280297Sjkim        PKCS8_PRIV_KEY_INFO_free(p8inf);
155280297Sjkim        return ret;
156280297Sjkim    }
157109998Smarkm}
158109998Smarkm
159280297SjkimEVP_PKEY *d2i_PKCS8PrivateKey_bio(BIO *bp, EVP_PKEY **x, pem_password_cb *cb,
160280297Sjkim                                  void *u)
161109998Smarkm{
162280297Sjkim    PKCS8_PRIV_KEY_INFO *p8inf = NULL;
163280297Sjkim    X509_SIG *p8 = NULL;
164280297Sjkim    int klen;
165280297Sjkim    EVP_PKEY *ret;
166280297Sjkim    char psbuf[PEM_BUFSIZE];
167280297Sjkim    p8 = d2i_PKCS8_bio(bp, NULL);
168280297Sjkim    if (!p8)
169280297Sjkim        return NULL;
170280297Sjkim    if (cb)
171280297Sjkim        klen = cb(psbuf, PEM_BUFSIZE, 0, u);
172280297Sjkim    else
173280297Sjkim        klen = PEM_def_callback(psbuf, PEM_BUFSIZE, 0, u);
174337982Sjkim    if (klen < 0) {
175280297Sjkim        PEMerr(PEM_F_D2I_PKCS8PRIVATEKEY_BIO, PEM_R_BAD_PASSWORD_READ);
176280297Sjkim        X509_SIG_free(p8);
177280297Sjkim        return NULL;
178280297Sjkim    }
179280297Sjkim    p8inf = PKCS8_decrypt(p8, psbuf, klen);
180280297Sjkim    X509_SIG_free(p8);
181325337Sjkim    OPENSSL_cleanse(psbuf, klen);
182280297Sjkim    if (!p8inf)
183280297Sjkim        return NULL;
184280297Sjkim    ret = EVP_PKCS82PKEY(p8inf);
185280297Sjkim    PKCS8_PRIV_KEY_INFO_free(p8inf);
186280297Sjkim    if (!ret)
187280297Sjkim        return NULL;
188280297Sjkim    if (x) {
189280297Sjkim        if (*x)
190280297Sjkim            EVP_PKEY_free(*x);
191280297Sjkim        *x = ret;
192280297Sjkim    }
193280297Sjkim    return ret;
194109998Smarkm}
195109998Smarkm
196109998Smarkm#ifndef OPENSSL_NO_FP_API
197109998Smarkm
198109998Smarkmint i2d_PKCS8PrivateKey_fp(FILE *fp, EVP_PKEY *x, const EVP_CIPHER *enc,
199280297Sjkim                           char *kstr, int klen, pem_password_cb *cb, void *u)
200109998Smarkm{
201280297Sjkim    return do_pk8pkey_fp(fp, x, 1, -1, enc, kstr, klen, cb, u);
202109998Smarkm}
203109998Smarkm
204109998Smarkmint i2d_PKCS8PrivateKey_nid_fp(FILE *fp, EVP_PKEY *x, int nid,
205280297Sjkim                               char *kstr, int klen,
206280297Sjkim                               pem_password_cb *cb, void *u)
207109998Smarkm{
208280297Sjkim    return do_pk8pkey_fp(fp, x, 1, nid, NULL, kstr, klen, cb, u);
209109998Smarkm}
210109998Smarkm
211109998Smarkmint PEM_write_PKCS8PrivateKey_nid(FILE *fp, EVP_PKEY *x, int nid,
212280297Sjkim                                  char *kstr, int klen,
213280297Sjkim                                  pem_password_cb *cb, void *u)
214109998Smarkm{
215280297Sjkim    return do_pk8pkey_fp(fp, x, 0, nid, NULL, kstr, klen, cb, u);
216109998Smarkm}
217109998Smarkm
218109998Smarkmint PEM_write_PKCS8PrivateKey(FILE *fp, EVP_PKEY *x, const EVP_CIPHER *enc,
219280297Sjkim                              char *kstr, int klen, pem_password_cb *cb,
220280297Sjkim                              void *u)
221109998Smarkm{
222280297Sjkim    return do_pk8pkey_fp(fp, x, 0, -1, enc, kstr, klen, cb, u);
223109998Smarkm}
224109998Smarkm
225280297Sjkimstatic int do_pk8pkey_fp(FILE *fp, EVP_PKEY *x, int isder, int nid,
226280297Sjkim                         const EVP_CIPHER *enc, char *kstr, int klen,
227280297Sjkim                         pem_password_cb *cb, void *u)
228109998Smarkm{
229280297Sjkim    BIO *bp;
230280297Sjkim    int ret;
231280297Sjkim    if (!(bp = BIO_new_fp(fp, BIO_NOCLOSE))) {
232280297Sjkim        PEMerr(PEM_F_DO_PK8PKEY_FP, ERR_R_BUF_LIB);
233280297Sjkim        return (0);
234280297Sjkim    }
235280297Sjkim    ret = do_pk8pkey(bp, x, isder, nid, enc, kstr, klen, cb, u);
236280297Sjkim    BIO_free(bp);
237280297Sjkim    return ret;
238109998Smarkm}
239109998Smarkm
240280297SjkimEVP_PKEY *d2i_PKCS8PrivateKey_fp(FILE *fp, EVP_PKEY **x, pem_password_cb *cb,
241280297Sjkim                                 void *u)
242109998Smarkm{
243280297Sjkim    BIO *bp;
244280297Sjkim    EVP_PKEY *ret;
245280297Sjkim    if (!(bp = BIO_new_fp(fp, BIO_NOCLOSE))) {
246280297Sjkim        PEMerr(PEM_F_D2I_PKCS8PRIVATEKEY_FP, ERR_R_BUF_LIB);
247280297Sjkim        return NULL;
248280297Sjkim    }
249280297Sjkim    ret = d2i_PKCS8PrivateKey_bio(bp, x, cb, u);
250280297Sjkim    BIO_free(bp);
251280297Sjkim    return ret;
252109998Smarkm}
253109998Smarkm
254109998Smarkm#endif
255109998Smarkm
256109998SmarkmIMPLEMENT_PEM_rw(PKCS8, X509_SIG, PEM_STRING_PKCS8, X509_SIG)
257280297Sjkim
258280297Sjkim
259109998SmarkmIMPLEMENT_PEM_rw(PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO, PEM_STRING_PKCS8INF,
260280297Sjkim             PKCS8_PRIV_KEY_INFO)
261