p_lib.c revision 296341
1/* crypto/evp/p_lib.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#include <stdio.h>
60#include "cryptlib.h"
61#include <openssl/bn.h>
62#include <openssl/err.h>
63#include <openssl/objects.h>
64#include <openssl/evp.h>
65#include <openssl/asn1_mac.h>
66#include <openssl/x509.h>
67#ifndef OPENSSL_NO_RSA
68# include <openssl/rsa.h>
69#endif
70#ifndef OPENSSL_NO_DSA
71# include <openssl/dsa.h>
72#endif
73#ifndef OPENSSL_NO_DH
74# include <openssl/dh.h>
75#endif
76
77#ifndef OPENSSL_NO_ENGINE
78# include <openssl/engine.h>
79#endif
80
81#include "asn1_locl.h"
82
83static void EVP_PKEY_free_it(EVP_PKEY *x);
84
85int EVP_PKEY_bits(EVP_PKEY *pkey)
86{
87    if (pkey && pkey->ameth && pkey->ameth->pkey_bits)
88        return pkey->ameth->pkey_bits(pkey);
89    return 0;
90}
91
92int EVP_PKEY_size(EVP_PKEY *pkey)
93{
94    if (pkey && pkey->ameth && pkey->ameth->pkey_size)
95        return pkey->ameth->pkey_size(pkey);
96    return 0;
97}
98
99int EVP_PKEY_save_parameters(EVP_PKEY *pkey, int mode)
100{
101#ifndef OPENSSL_NO_DSA
102    if (pkey->type == EVP_PKEY_DSA) {
103        int ret = pkey->save_parameters;
104
105        if (mode >= 0)
106            pkey->save_parameters = mode;
107        return (ret);
108    }
109#endif
110#ifndef OPENSSL_NO_EC
111    if (pkey->type == EVP_PKEY_EC) {
112        int ret = pkey->save_parameters;
113
114        if (mode >= 0)
115            pkey->save_parameters = mode;
116        return (ret);
117    }
118#endif
119    return (0);
120}
121
122int EVP_PKEY_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from)
123{
124    if (to->type != from->type) {
125        EVPerr(EVP_F_EVP_PKEY_COPY_PARAMETERS, EVP_R_DIFFERENT_KEY_TYPES);
126        goto err;
127    }
128
129    if (EVP_PKEY_missing_parameters(from)) {
130        EVPerr(EVP_F_EVP_PKEY_COPY_PARAMETERS, EVP_R_MISSING_PARAMETERS);
131        goto err;
132    }
133    if (from->ameth && from->ameth->param_copy)
134        return from->ameth->param_copy(to, from);
135 err:
136    return 0;
137}
138
139int EVP_PKEY_missing_parameters(const EVP_PKEY *pkey)
140{
141    if (pkey->ameth && pkey->ameth->param_missing)
142        return pkey->ameth->param_missing(pkey);
143    return 0;
144}
145
146int EVP_PKEY_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b)
147{
148    if (a->type != b->type)
149        return -1;
150    if (a->ameth && a->ameth->param_cmp)
151        return a->ameth->param_cmp(a, b);
152    return -2;
153}
154
155int EVP_PKEY_cmp(const EVP_PKEY *a, const EVP_PKEY *b)
156{
157    if (a->type != b->type)
158        return -1;
159
160    if (a->ameth) {
161        int ret;
162        /* Compare parameters if the algorithm has them */
163        if (a->ameth->param_cmp) {
164            ret = a->ameth->param_cmp(a, b);
165            if (ret <= 0)
166                return ret;
167        }
168
169        if (a->ameth->pub_cmp)
170            return a->ameth->pub_cmp(a, b);
171    }
172
173    return -2;
174}
175
176EVP_PKEY *EVP_PKEY_new(void)
177{
178    EVP_PKEY *ret;
179
180    ret = (EVP_PKEY *)OPENSSL_malloc(sizeof(EVP_PKEY));
181    if (ret == NULL) {
182        EVPerr(EVP_F_EVP_PKEY_NEW, ERR_R_MALLOC_FAILURE);
183        return (NULL);
184    }
185    ret->type = EVP_PKEY_NONE;
186    ret->save_type = EVP_PKEY_NONE;
187    ret->references = 1;
188    ret->ameth = NULL;
189    ret->engine = NULL;
190    ret->pkey.ptr = NULL;
191    ret->attributes = NULL;
192    ret->save_parameters = 1;
193    return (ret);
194}
195
196/*
197 * Setup a public key ASN1 method and ENGINE from a NID or a string. If pkey
198 * is NULL just return 1 or 0 if the algorithm exists.
199 */
200
201static int pkey_set_type(EVP_PKEY *pkey, int type, const char *str, int len)
202{
203    const EVP_PKEY_ASN1_METHOD *ameth;
204    ENGINE *e = NULL;
205    if (pkey) {
206        if (pkey->pkey.ptr)
207            EVP_PKEY_free_it(pkey);
208        /*
209         * If key type matches and a method exists then this lookup has
210         * succeeded once so just indicate success.
211         */
212        if ((type == pkey->save_type) && pkey->ameth)
213            return 1;
214#ifndef OPENSSL_NO_ENGINE
215        /* If we have an ENGINE release it */
216        if (pkey->engine) {
217            ENGINE_finish(pkey->engine);
218            pkey->engine = NULL;
219        }
220#endif
221    }
222    if (str)
223        ameth = EVP_PKEY_asn1_find_str(&e, str, len);
224    else
225        ameth = EVP_PKEY_asn1_find(&e, type);
226#ifndef OPENSSL_NO_ENGINE
227    if (!pkey && e)
228        ENGINE_finish(e);
229#endif
230    if (!ameth) {
231        EVPerr(EVP_F_PKEY_SET_TYPE, EVP_R_UNSUPPORTED_ALGORITHM);
232        return 0;
233    }
234    if (pkey) {
235        pkey->ameth = ameth;
236        pkey->engine = e;
237
238        pkey->type = pkey->ameth->pkey_id;
239        pkey->save_type = type;
240    }
241    return 1;
242}
243
244int EVP_PKEY_set_type(EVP_PKEY *pkey, int type)
245{
246    return pkey_set_type(pkey, type, NULL, -1);
247}
248
249int EVP_PKEY_set_type_str(EVP_PKEY *pkey, const char *str, int len)
250{
251    return pkey_set_type(pkey, EVP_PKEY_NONE, str, len);
252}
253
254int EVP_PKEY_assign(EVP_PKEY *pkey, int type, void *key)
255{
256    if (!EVP_PKEY_set_type(pkey, type))
257        return 0;
258    pkey->pkey.ptr = key;
259    return (key != NULL);
260}
261
262void *EVP_PKEY_get0(EVP_PKEY *pkey)
263{
264    return pkey->pkey.ptr;
265}
266
267#ifndef OPENSSL_NO_RSA
268int EVP_PKEY_set1_RSA(EVP_PKEY *pkey, RSA *key)
269{
270    int ret = EVP_PKEY_assign_RSA(pkey, key);
271    if (ret)
272        RSA_up_ref(key);
273    return ret;
274}
275
276RSA *EVP_PKEY_get1_RSA(EVP_PKEY *pkey)
277{
278    if (pkey->type != EVP_PKEY_RSA) {
279        EVPerr(EVP_F_EVP_PKEY_GET1_RSA, EVP_R_EXPECTING_AN_RSA_KEY);
280        return NULL;
281    }
282    RSA_up_ref(pkey->pkey.rsa);
283    return pkey->pkey.rsa;
284}
285#endif
286
287#ifndef OPENSSL_NO_DSA
288int EVP_PKEY_set1_DSA(EVP_PKEY *pkey, DSA *key)
289{
290    int ret = EVP_PKEY_assign_DSA(pkey, key);
291    if (ret)
292        DSA_up_ref(key);
293    return ret;
294}
295
296DSA *EVP_PKEY_get1_DSA(EVP_PKEY *pkey)
297{
298    if (pkey->type != EVP_PKEY_DSA) {
299        EVPerr(EVP_F_EVP_PKEY_GET1_DSA, EVP_R_EXPECTING_A_DSA_KEY);
300        return NULL;
301    }
302    DSA_up_ref(pkey->pkey.dsa);
303    return pkey->pkey.dsa;
304}
305#endif
306
307#ifndef OPENSSL_NO_EC
308
309int EVP_PKEY_set1_EC_KEY(EVP_PKEY *pkey, EC_KEY *key)
310{
311    int ret = EVP_PKEY_assign_EC_KEY(pkey, key);
312    if (ret)
313        EC_KEY_up_ref(key);
314    return ret;
315}
316
317EC_KEY *EVP_PKEY_get1_EC_KEY(EVP_PKEY *pkey)
318{
319    if (pkey->type != EVP_PKEY_EC) {
320        EVPerr(EVP_F_EVP_PKEY_GET1_EC_KEY, EVP_R_EXPECTING_A_EC_KEY);
321        return NULL;
322    }
323    EC_KEY_up_ref(pkey->pkey.ec);
324    return pkey->pkey.ec;
325}
326#endif
327
328#ifndef OPENSSL_NO_DH
329
330int EVP_PKEY_set1_DH(EVP_PKEY *pkey, DH *key)
331{
332    int ret = EVP_PKEY_assign_DH(pkey, key);
333    if (ret)
334        DH_up_ref(key);
335    return ret;
336}
337
338DH *EVP_PKEY_get1_DH(EVP_PKEY *pkey)
339{
340    if (pkey->type != EVP_PKEY_DH) {
341        EVPerr(EVP_F_EVP_PKEY_GET1_DH, EVP_R_EXPECTING_A_DH_KEY);
342        return NULL;
343    }
344    DH_up_ref(pkey->pkey.dh);
345    return pkey->pkey.dh;
346}
347#endif
348
349int EVP_PKEY_type(int type)
350{
351    int ret;
352    const EVP_PKEY_ASN1_METHOD *ameth;
353    ENGINE *e;
354    ameth = EVP_PKEY_asn1_find(&e, type);
355    if (ameth)
356        ret = ameth->pkey_id;
357    else
358        ret = NID_undef;
359#ifndef OPENSSL_NO_ENGINE
360    if (e)
361        ENGINE_finish(e);
362#endif
363    return ret;
364}
365
366int EVP_PKEY_id(const EVP_PKEY *pkey)
367{
368    return pkey->type;
369}
370
371int EVP_PKEY_base_id(const EVP_PKEY *pkey)
372{
373    return EVP_PKEY_type(pkey->type);
374}
375
376void EVP_PKEY_free(EVP_PKEY *x)
377{
378    int i;
379
380    if (x == NULL)
381        return;
382
383    i = CRYPTO_add(&x->references, -1, CRYPTO_LOCK_EVP_PKEY);
384#ifdef REF_PRINT
385    REF_PRINT("EVP_PKEY", x);
386#endif
387    if (i > 0)
388        return;
389#ifdef REF_CHECK
390    if (i < 0) {
391        fprintf(stderr, "EVP_PKEY_free, bad reference count\n");
392        abort();
393    }
394#endif
395    EVP_PKEY_free_it(x);
396    if (x->attributes)
397        sk_X509_ATTRIBUTE_pop_free(x->attributes, X509_ATTRIBUTE_free);
398    OPENSSL_free(x);
399}
400
401static void EVP_PKEY_free_it(EVP_PKEY *x)
402{
403    if (x->ameth && x->ameth->pkey_free) {
404        x->ameth->pkey_free(x);
405        x->pkey.ptr = NULL;
406    }
407#ifndef OPENSSL_NO_ENGINE
408    if (x->engine) {
409        ENGINE_finish(x->engine);
410        x->engine = NULL;
411    }
412#endif
413}
414
415static int unsup_alg(BIO *out, const EVP_PKEY *pkey, int indent,
416                     const char *kstr)
417{
418    BIO_indent(out, indent, 128);
419    BIO_printf(out, "%s algorithm \"%s\" unsupported\n",
420               kstr, OBJ_nid2ln(pkey->type));
421    return 1;
422}
423
424int EVP_PKEY_print_public(BIO *out, const EVP_PKEY *pkey,
425                          int indent, ASN1_PCTX *pctx)
426{
427    if (pkey->ameth && pkey->ameth->pub_print)
428        return pkey->ameth->pub_print(out, pkey, indent, pctx);
429
430    return unsup_alg(out, pkey, indent, "Public Key");
431}
432
433int EVP_PKEY_print_private(BIO *out, const EVP_PKEY *pkey,
434                           int indent, ASN1_PCTX *pctx)
435{
436    if (pkey->ameth && pkey->ameth->priv_print)
437        return pkey->ameth->priv_print(out, pkey, indent, pctx);
438
439    return unsup_alg(out, pkey, indent, "Private Key");
440}
441
442int EVP_PKEY_print_params(BIO *out, const EVP_PKEY *pkey,
443                          int indent, ASN1_PCTX *pctx)
444{
445    if (pkey->ameth && pkey->ameth->param_print)
446        return pkey->ameth->param_print(out, pkey, indent, pctx);
447    return unsup_alg(out, pkey, indent, "Parameters");
448}
449
450int EVP_PKEY_get_default_digest_nid(EVP_PKEY *pkey, int *pnid)
451{
452    if (!pkey->ameth || !pkey->ameth->pkey_ctrl)
453        return -2;
454    return pkey->ameth->pkey_ctrl(pkey, ASN1_PKEY_CTRL_DEFAULT_MD_NID,
455                                  0, pnid);
456}
457