From a43ce912fc025d11e1395506111f75fc194d7ba5 Mon Sep 17 00:00:00 2001 From: Jung-uk Kim Date: Thu, 13 Sep 2018 19:18:07 +0000 Subject: Import OpenSSL 1.1.1. --- crypto/x509/x_pubkey.c | 374 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 374 insertions(+) create mode 100644 crypto/x509/x_pubkey.c (limited to 'crypto/x509/x_pubkey.c') diff --git a/crypto/x509/x_pubkey.c b/crypto/x509/x_pubkey.c new file mode 100644 index 000000000000..d050b0b4b3e2 --- /dev/null +++ b/crypto/x509/x_pubkey.c @@ -0,0 +1,374 @@ +/* + * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. + * + * 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 +#include "internal/cryptlib.h" +#include +#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_FREE_POST) { + X509_PUBKEY *pubkey = (X509_PUBKEY *)*pval; + 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; +} + +ASN1_SEQUENCE_cb(X509_PUBKEY, pubkey_cb) = { + ASN1_SIMPLE(X509_PUBKEY, algor, X509_ALGOR), + ASN1_SIMPLE(X509_PUBKEY, public_key, ASN1_BIT_STRING) +} ASN1_SEQUENCE_END_cb(X509_PUBKEY, X509_PUBKEY) + +IMPLEMENT_ASN1_FUNCTIONS(X509_PUBKEY) + +int X509_PUBKEY_set(X509_PUBKEY **x, EVP_PKEY *pkey) +{ + X509_PUBKEY *pk = NULL; + + if (x == NULL) + return 0; + + if ((pk = X509_PUBKEY_new()) == NULL) + goto error; + + if (pkey->ameth) { + if (pkey->ameth->pub_encode) { + if (!pkey->ameth->pub_encode(pk, pkey)) { + X509err(X509_F_X509_PUBKEY_SET, + X509_R_PUBLIC_KEY_ENCODE_ERROR); + goto error; + } + } else { + X509err(X509_F_X509_PUBKEY_SET, X509_R_METHOD_NOT_SUPPORTED); + goto error; + } + } else { + X509err(X509_F_X509_PUBKEY_SET, X509_R_UNSUPPORTED_ALGORITHM); + goto error; + } + + X509_PUBKEY_free(*x); + *x = pk; + pk->pkey = pkey; + EVP_PKEY_up_ref(pkey); + return 1; + + error: + X509_PUBKEY_free(pk); + return 0; +} + +/* + * 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. + */ + + +static int x509_pubkey_decode(EVP_PKEY **ppkey, X509_PUBKEY *key) +{ + EVP_PKEY *pkey = EVP_PKEY_new(); + + if (pkey == NULL) { + X509err(X509_F_X509_PUBKEY_DECODE, ERR_R_MALLOC_FAILURE); + return -1; + } + + if (!EVP_PKEY_set_type(pkey, OBJ_obj2nid(key->algor->algorithm))) { + X509err(X509_F_X509_PUBKEY_DECODE, X509_R_UNSUPPORTED_ALGORITHM); + goto 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_DECODE, X509_R_METHOD_NOT_SUPPORTED); + goto error; + } + + *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); + } + + return NULL; +} + +EVP_PKEY *X509_PUBKEY_get(X509_PUBKEY *key) +{ + EVP_PKEY *ret = X509_PUBKEY_get0(key); + if (ret != NULL) + EVP_PKEY_up_ref(ret); + return ret; +} + +/* + * Now two pseudo ASN1 routines that take an EVP_PKEY structure and encode or + * decode as X509_PUBKEY + */ + +EVP_PKEY *d2i_PUBKEY(EVP_PKEY **a, const unsigned char **pp, long length) +{ + X509_PUBKEY *xpk; + EVP_PKEY *pktmp; + const unsigned char *q; + q = *pp; + xpk = d2i_X509_PUBKEY(NULL, &q, length); + if (!xpk) + return NULL; + pktmp = X509_PUBKEY_get(xpk); + X509_PUBKEY_free(xpk); + if (!pktmp) + return NULL; + *pp = q; + if (a) { + EVP_PKEY_free(*a); + *a = pktmp; + } + return pktmp; +} + +int i2d_PUBKEY(EVP_PKEY *a, unsigned char **pp) +{ + X509_PUBKEY *xpk = NULL; + int ret; + if (!a) + return 0; + if (!X509_PUBKEY_set(&xpk, a)) + return -1; + ret = i2d_X509_PUBKEY(xpk, pp); + X509_PUBKEY_free(xpk); + return ret; +} + +/* + * The following are equivalents but which return RSA and DSA keys + */ +#ifndef OPENSSL_NO_RSA +RSA *d2i_RSA_PUBKEY(RSA **a, const unsigned char **pp, long length) +{ + EVP_PKEY *pkey; + RSA *key; + const unsigned char *q; + q = *pp; + pkey = d2i_PUBKEY(NULL, &q, length); + if (!pkey) + return NULL; + key = EVP_PKEY_get1_RSA(pkey); + EVP_PKEY_free(pkey); + if (!key) + return NULL; + *pp = q; + if (a) { + RSA_free(*a); + *a = key; + } + return key; +} + +int i2d_RSA_PUBKEY(RSA *a, unsigned char **pp) +{ + EVP_PKEY *pktmp; + int ret; + if (!a) + return 0; + pktmp = EVP_PKEY_new(); + if (pktmp == NULL) { + ASN1err(ASN1_F_I2D_RSA_PUBKEY, ERR_R_MALLOC_FAILURE); + return -1; + } + EVP_PKEY_set1_RSA(pktmp, a); + ret = i2d_PUBKEY(pktmp, pp); + EVP_PKEY_free(pktmp); + return ret; +} +#endif + +#ifndef OPENSSL_NO_DSA +DSA *d2i_DSA_PUBKEY(DSA **a, const unsigned char **pp, long length) +{ + EVP_PKEY *pkey; + DSA *key; + const unsigned char *q; + q = *pp; + pkey = d2i_PUBKEY(NULL, &q, length); + if (!pkey) + return NULL; + key = EVP_PKEY_get1_DSA(pkey); + EVP_PKEY_free(pkey); + if (!key) + return NULL; + *pp = q; + if (a) { + DSA_free(*a); + *a = key; + } + return key; +} + +int i2d_DSA_PUBKEY(DSA *a, unsigned char **pp) +{ + EVP_PKEY *pktmp; + int ret; + if (!a) + return 0; + pktmp = EVP_PKEY_new(); + if (pktmp == NULL) { + ASN1err(ASN1_F_I2D_DSA_PUBKEY, ERR_R_MALLOC_FAILURE); + return -1; + } + EVP_PKEY_set1_DSA(pktmp, a); + ret = i2d_PUBKEY(pktmp, pp); + EVP_PKEY_free(pktmp); + return ret; +} +#endif + +#ifndef OPENSSL_NO_EC +EC_KEY *d2i_EC_PUBKEY(EC_KEY **a, const unsigned char **pp, long length) +{ + EVP_PKEY *pkey; + EC_KEY *key; + const unsigned char *q; + q = *pp; + pkey = d2i_PUBKEY(NULL, &q, length); + if (!pkey) + return NULL; + key = EVP_PKEY_get1_EC_KEY(pkey); + EVP_PKEY_free(pkey); + if (!key) + return NULL; + *pp = q; + if (a) { + EC_KEY_free(*a); + *a = key; + } + return key; +} + +int i2d_EC_PUBKEY(EC_KEY *a, unsigned char **pp) +{ + EVP_PKEY *pktmp; + int ret; + if (!a) + return 0; + if ((pktmp = EVP_PKEY_new()) == NULL) { + ASN1err(ASN1_F_I2D_EC_PUBKEY, ERR_R_MALLOC_FAILURE); + return -1; + } + EVP_PKEY_set1_EC_KEY(pktmp, a); + ret = i2d_PUBKEY(pktmp, pp); + EVP_PKEY_free(pktmp); + return ret; +} +#endif + +int X509_PUBKEY_set0_param(X509_PUBKEY *pub, ASN1_OBJECT *aobj, + int ptype, void *pval, + unsigned char *penc, int penclen) +{ + if (!X509_ALGOR_set0(pub->algor, aobj, ptype, pval)) + return 0; + if (penc) { + OPENSSL_free(pub->public_key->data); + pub->public_key->data = penc; + pub->public_key->length = penclen; + /* Set number of unused bits to zero */ + pub->public_key->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07); + pub->public_key->flags |= ASN1_STRING_FLAG_BITS_LEFT; + } + return 1; +} + +int X509_PUBKEY_get0_param(ASN1_OBJECT **ppkalg, + const unsigned char **pk, int *ppklen, + X509_ALGOR **pa, X509_PUBKEY *pub) +{ + if (ppkalg) + *ppkalg = pub->algor->algorithm; + if (pk) { + *pk = pub->public_key->data; + *ppklen = pub->public_key->length; + } + if (pa) + *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; +} -- cgit v1.2.3