X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=crypto%2Fx509%2Fx_pubkey.c;h=cc692834d1fa8a951151e1fe5f51316fb6674c78;hb=c8223538cb05e5aac6418a5ba6dc4775b7ab486b;hp=158d1d26aff3c01f5989ffb88713b08778862827;hpb=91829e456c998eb9c2e565307b8f1022481049ce;p=oweals%2Fopenssl.git diff --git a/crypto/x509/x_pubkey.c b/crypto/x509/x_pubkey.c index 158d1d26af..cc692834d1 100644 --- a/crypto/x509/x_pubkey.c +++ b/crypto/x509/x_pubkey.c @@ -1,58 +1,10 @@ -/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) - * All rights reserved. - * - * This package is an SSL implementation written - * by Eric Young (eay@cryptsoft.com). - * The implementation was written so as to conform with Netscapes SSL. - * - * This library is free for commercial and non-commercial use as long as - * the following conditions are aheared to. The following conditions - * apply to all code found in this distribution, be it the RC4, RSA, - * lhash, DES, etc., code; not just the SSL code. The SSL documentation - * included with this distribution is covered by the same copyright terms - * except that the holder is Tim Hudson (tjh@cryptsoft.com). - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. - * If this package is used in a product, Eric Young should be given attribution - * as the author of the parts of the library used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * "This product includes cryptographic software written by - * Eric Young (eay@cryptsoft.com)" - * The word 'cryptographic' can be left out if the rouines from the library - * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from - * the apps directory (application code) you must include an acknowledgement: - * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html */ #include @@ -61,23 +13,38 @@ #include #include "internal/asn1_int.h" #include "internal/evp_int.h" +#include "internal/x509_int.h" #include #include +struct X509_pubkey_st { + X509_ALGOR *algor; + ASN1_BIT_STRING *public_key; + EVP_PKEY *pkey; +}; + +static int x509_pubkey_decode(EVP_PKEY **pk, X509_PUBKEY *key); + /* Minor tweak to operation: free up EVP_PKEY */ static int pubkey_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, void *exarg) { - if (operation == ASN1_OP_NEW_POST) { - X509_PUBKEY *pubkey = (X509_PUBKEY *)*pval; - pubkey->lock = CRYPTO_THREAD_lock_new(); - if (pubkey->lock == NULL) - return 0; - } if (operation == ASN1_OP_FREE_POST) { X509_PUBKEY *pubkey = (X509_PUBKEY *)*pval; - CRYPTO_THREAD_lock_free(pubkey->lock); EVP_PKEY_free(pubkey->pkey); + } else if (operation == ASN1_OP_D2I_POST) { + /* Attempt to decode public key and cache in pubkey structure. */ + X509_PUBKEY *pubkey = (X509_PUBKEY *)*pval; + EVP_PKEY_free(pubkey->pkey); + /* + * Opportunistically decode the key but remove any non fatal errors + * from the queue. Subsequent explicit attempts to decode/use the key + * will return an appropriate error. + */ + ERR_set_mark(); + if (x509_pubkey_decode(&pubkey->pkey, pubkey) == -1) + return 0; + ERR_pop_to_mark(); } return 1; } @@ -117,6 +84,8 @@ int X509_PUBKEY_set(X509_PUBKEY **x, EVP_PKEY *pkey) X509_PUBKEY_free(*x); *x = pk; + pk->pkey = pkey; + EVP_PKEY_up_ref(pkey); return 1; error: @@ -124,55 +93,76 @@ int X509_PUBKEY_set(X509_PUBKEY **x, EVP_PKEY *pkey) return 0; } -EVP_PKEY *X509_PUBKEY_get0(X509_PUBKEY *key) -{ - EVP_PKEY *ret = NULL; - - if (key == NULL) - goto error; +/* + * Attempt to decode a public key. + * Returns 1 on success, 0 for a decode failure and -1 for a fatal + * error e.g. malloc failure. + */ - if (key->pkey != NULL) - return key->pkey; - if (key->public_key == NULL) - goto error; +static int x509_pubkey_decode(EVP_PKEY **ppkey, X509_PUBKEY *key) + { + EVP_PKEY *pkey = EVP_PKEY_new(); - if ((ret = EVP_PKEY_new()) == NULL) { - X509err(X509_F_X509_PUBKEY_GET0, ERR_R_MALLOC_FAILURE); - goto error; + if (pkey == NULL) { + X509err(X509_F_X509_PUBKEY_DECODE, ERR_R_MALLOC_FAILURE); + return -1; } - if (!EVP_PKEY_set_type(ret, OBJ_obj2nid(key->algor->algorithm))) { - X509err(X509_F_X509_PUBKEY_GET0, X509_R_UNSUPPORTED_ALGORITHM); + if (!EVP_PKEY_set_type(pkey, OBJ_obj2nid(key->algor->algorithm))) { + X509err(X509_F_X509_PUBKEY_DECODE, X509_R_UNSUPPORTED_ALGORITHM); goto error; } - if (ret->ameth->pub_decode) { - if (!ret->ameth->pub_decode(ret, key)) { - X509err(X509_F_X509_PUBKEY_GET0, X509_R_PUBLIC_KEY_DECODE_ERROR); + if (pkey->ameth->pub_decode) { + /* + * Treat any failure of pub_decode as a decode error. In + * future we could have different return codes for decode + * errors and fatal errors such as malloc failure. + */ + if (!pkey->ameth->pub_decode(pkey, key)) { + X509err(X509_F_X509_PUBKEY_DECODE, X509_R_PUBLIC_KEY_DECODE_ERROR); goto error; } } else { - X509err(X509_F_X509_PUBKEY_GET0, X509_R_METHOD_NOT_SUPPORTED); + X509err(X509_F_X509_PUBKEY_DECODE, X509_R_METHOD_NOT_SUPPORTED); goto error; } - /* Check to see if another thread set key->pkey first */ - CRYPTO_THREAD_write_lock(key->lock); - if (key->pkey) { - CRYPTO_THREAD_unlock(key->lock); + *ppkey = pkey; + return 1; + + error: + EVP_PKEY_free(pkey); + return 0; +} + +EVP_PKEY *X509_PUBKEY_get0(X509_PUBKEY *key) +{ + EVP_PKEY *ret = NULL; + + if (key == NULL || key->public_key == NULL) + return NULL; + + if (key->pkey != NULL) + return key->pkey; + + /* + * When the key ASN.1 is initially parsed an attempt is made to + * decode the public key and cache the EVP_PKEY structure. If this + * operation fails the cached value will be NULL. Parsing continues + * to allow parsing of unknown key types or unsupported forms. + * We repeat the decode operation so the appropriate errors are left + * in the queue. + */ + x509_pubkey_decode(&ret, key); + /* If decode doesn't fail something bad happened */ + if (ret != NULL) { + X509err(X509_F_X509_PUBKEY_GET0, ERR_R_INTERNAL_ERROR); EVP_PKEY_free(ret); - ret = key->pkey; - } else { - key->pkey = ret; - CRYPTO_THREAD_unlock(key->lock); } - return ret; - - error: - EVP_PKEY_free(ret); - return (NULL); + return NULL; } EVP_PKEY *X509_PUBKEY_get(X509_PUBKEY *key) @@ -375,3 +365,10 @@ int X509_PUBKEY_get0_param(ASN1_OBJECT **ppkalg, *pa = pub->algor; return 1; } + +ASN1_BIT_STRING *X509_get0_pubkey_bitstr(const X509 *x) +{ + if (x == NULL) + return NULL; + return x->cert_info.key->public_key; +}