125b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* crypto/evp/p_lib.c */ 225b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 325b3c049e70834cf33790a28643ab058b507b35cBen Cheng * All rights reserved. 425b3c049e70834cf33790a28643ab058b507b35cBen Cheng * 525b3c049e70834cf33790a28643ab058b507b35cBen Cheng * This package is an SSL implementation written 625b3c049e70834cf33790a28643ab058b507b35cBen Cheng * by Eric Young (eay@cryptsoft.com). 725b3c049e70834cf33790a28643ab058b507b35cBen Cheng * The implementation was written so as to conform with Netscapes SSL. 825b3c049e70834cf33790a28643ab058b507b35cBen Cheng * 925b3c049e70834cf33790a28643ab058b507b35cBen Cheng * This library is free for commercial and non-commercial use as long as 1025b3c049e70834cf33790a28643ab058b507b35cBen Cheng * the following conditions are aheared to. The following conditions 1125b3c049e70834cf33790a28643ab058b507b35cBen Cheng * apply to all code found in this distribution, be it the RC4, RSA, 1225b3c049e70834cf33790a28643ab058b507b35cBen Cheng * lhash, DES, etc., code; not just the SSL code. The SSL documentation 1325b3c049e70834cf33790a28643ab058b507b35cBen Cheng * included with this distribution is covered by the same copyright terms 1425b3c049e70834cf33790a28643ab058b507b35cBen Cheng * except that the holder is Tim Hudson (tjh@cryptsoft.com). 1525b3c049e70834cf33790a28643ab058b507b35cBen Cheng * 1625b3c049e70834cf33790a28643ab058b507b35cBen Cheng * Copyright remains Eric Young's, and as such any Copyright notices in 1725b3c049e70834cf33790a28643ab058b507b35cBen Cheng * the code are not to be removed. 1825b3c049e70834cf33790a28643ab058b507b35cBen Cheng * If this package is used in a product, Eric Young should be given attribution 1925b3c049e70834cf33790a28643ab058b507b35cBen Cheng * as the author of the parts of the library used. 2025b3c049e70834cf33790a28643ab058b507b35cBen Cheng * This can be in the form of a textual message at program startup or 2125b3c049e70834cf33790a28643ab058b507b35cBen Cheng * in documentation (online or textual) provided with the package. 2225b3c049e70834cf33790a28643ab058b507b35cBen Cheng * 2325b3c049e70834cf33790a28643ab058b507b35cBen Cheng * Redistribution and use in source and binary forms, with or without 2425b3c049e70834cf33790a28643ab058b507b35cBen Cheng * modification, are permitted provided that the following conditions 2525b3c049e70834cf33790a28643ab058b507b35cBen Cheng * are met: 2625b3c049e70834cf33790a28643ab058b507b35cBen Cheng * 1. Redistributions of source code must retain the copyright 2725b3c049e70834cf33790a28643ab058b507b35cBen Cheng * notice, this list of conditions and the following disclaimer. 2825b3c049e70834cf33790a28643ab058b507b35cBen Cheng * 2. Redistributions in binary form must reproduce the above copyright 2925b3c049e70834cf33790a28643ab058b507b35cBen Cheng * notice, this list of conditions and the following disclaimer in the 3025b3c049e70834cf33790a28643ab058b507b35cBen Cheng * documentation and/or other materials provided with the distribution. 3125b3c049e70834cf33790a28643ab058b507b35cBen Cheng * 3. All advertising materials mentioning features or use of this software 3225b3c049e70834cf33790a28643ab058b507b35cBen Cheng * must display the following acknowledgement: 3325b3c049e70834cf33790a28643ab058b507b35cBen Cheng * "This product includes cryptographic software written by 3425b3c049e70834cf33790a28643ab058b507b35cBen Cheng * Eric Young (eay@cryptsoft.com)" 3525b3c049e70834cf33790a28643ab058b507b35cBen Cheng * The word 'cryptographic' can be left out if the rouines from the library 3625b3c049e70834cf33790a28643ab058b507b35cBen Cheng * being used are not cryptographic related :-). 3725b3c049e70834cf33790a28643ab058b507b35cBen Cheng * 4. If you include any Windows specific code (or a derivative thereof) from 3825b3c049e70834cf33790a28643ab058b507b35cBen Cheng * the apps directory (application code) you must include an acknowledgement: 3925b3c049e70834cf33790a28643ab058b507b35cBen Cheng * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 4025b3c049e70834cf33790a28643ab058b507b35cBen Cheng * 4125b3c049e70834cf33790a28643ab058b507b35cBen Cheng * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 4225b3c049e70834cf33790a28643ab058b507b35cBen Cheng * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4325b3c049e70834cf33790a28643ab058b507b35cBen Cheng * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 4425b3c049e70834cf33790a28643ab058b507b35cBen Cheng * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 4525b3c049e70834cf33790a28643ab058b507b35cBen Cheng * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 4625b3c049e70834cf33790a28643ab058b507b35cBen Cheng * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 4725b3c049e70834cf33790a28643ab058b507b35cBen Cheng * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4825b3c049e70834cf33790a28643ab058b507b35cBen Cheng * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 4925b3c049e70834cf33790a28643ab058b507b35cBen Cheng * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5025b3c049e70834cf33790a28643ab058b507b35cBen Cheng * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5125b3c049e70834cf33790a28643ab058b507b35cBen Cheng * SUCH DAMAGE. 5225b3c049e70834cf33790a28643ab058b507b35cBen Cheng * 538701663f8720eaae76448f5d61890e142a67eba1Ben Cheng * The licence and distribution terms for any publically available version or 548701663f8720eaae76448f5d61890e142a67eba1Ben Cheng * derivative of this code cannot be changed. i.e. this code cannot simply be 558701663f8720eaae76448f5d61890e142a67eba1Ben Cheng * copied and put under another distribution licence 5625b3c049e70834cf33790a28643ab058b507b35cBen Cheng * [including the GNU Public Licence.] 5725b3c049e70834cf33790a28643ab058b507b35cBen Cheng */ 5825b3c049e70834cf33790a28643ab058b507b35cBen Cheng 5925b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <stdio.h> 6025b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include "cryptlib.h" 6125b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <openssl/bn.h> 6225b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <openssl/err.h> 6325b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <openssl/objects.h> 6425b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <openssl/evp.h> 6525b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <openssl/asn1_mac.h> 6625b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <openssl/x509.h> 6725b3c049e70834cf33790a28643ab058b507b35cBen Cheng#ifndef OPENSSL_NO_RSA 6825b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <openssl/rsa.h> 6925b3c049e70834cf33790a28643ab058b507b35cBen Cheng#endif 7025b3c049e70834cf33790a28643ab058b507b35cBen Cheng#ifndef OPENSSL_NO_DSA 7125b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <openssl/dsa.h> 7225b3c049e70834cf33790a28643ab058b507b35cBen Cheng#endif 7325b3c049e70834cf33790a28643ab058b507b35cBen Cheng#ifndef OPENSSL_NO_DH 7425b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <openssl/dh.h> 7525b3c049e70834cf33790a28643ab058b507b35cBen Cheng#endif 7625b3c049e70834cf33790a28643ab058b507b35cBen Cheng 7725b3c049e70834cf33790a28643ab058b507b35cBen Cheng#ifndef OPENSSL_NO_ENGINE 7825b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <openssl/engine.h> 7925b3c049e70834cf33790a28643ab058b507b35cBen Cheng#endif 8025b3c049e70834cf33790a28643ab058b507b35cBen Cheng 8125b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include "asn1_locl.h" 8225b3c049e70834cf33790a28643ab058b507b35cBen Cheng 8325b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic void EVP_PKEY_free_it(EVP_PKEY *x); 8425b3c049e70834cf33790a28643ab058b507b35cBen Cheng 8525b3c049e70834cf33790a28643ab058b507b35cBen Chengint EVP_PKEY_bits(EVP_PKEY *pkey) 8625b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 8725b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (pkey && pkey->ameth && pkey->ameth->pkey_bits) 8825b3c049e70834cf33790a28643ab058b507b35cBen Cheng return pkey->ameth->pkey_bits(pkey); 8925b3c049e70834cf33790a28643ab058b507b35cBen Cheng return 0; 9025b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 9125b3c049e70834cf33790a28643ab058b507b35cBen Cheng 9225b3c049e70834cf33790a28643ab058b507b35cBen Chengint EVP_PKEY_size(EVP_PKEY *pkey) 9325b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 9425b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (pkey && pkey->ameth && pkey->ameth->pkey_size) 9525b3c049e70834cf33790a28643ab058b507b35cBen Cheng return pkey->ameth->pkey_size(pkey); 9625b3c049e70834cf33790a28643ab058b507b35cBen Cheng return 0; 9725b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 9825b3c049e70834cf33790a28643ab058b507b35cBen Cheng 9925b3c049e70834cf33790a28643ab058b507b35cBen Chengint EVP_PKEY_save_parameters(EVP_PKEY *pkey, int mode) 10025b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 10125b3c049e70834cf33790a28643ab058b507b35cBen Cheng#ifndef OPENSSL_NO_DSA 10225b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (pkey->type == EVP_PKEY_DSA) 10325b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 10425b3c049e70834cf33790a28643ab058b507b35cBen Cheng int ret=pkey->save_parameters; 10525b3c049e70834cf33790a28643ab058b507b35cBen Cheng 10625b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (mode >= 0) 10725b3c049e70834cf33790a28643ab058b507b35cBen Cheng pkey->save_parameters=mode; 10825b3c049e70834cf33790a28643ab058b507b35cBen Cheng return(ret); 10925b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 11025b3c049e70834cf33790a28643ab058b507b35cBen Cheng#endif 11125b3c049e70834cf33790a28643ab058b507b35cBen Cheng#ifndef OPENSSL_NO_EC 11225b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (pkey->type == EVP_PKEY_EC) 11325b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 11425b3c049e70834cf33790a28643ab058b507b35cBen Cheng int ret = pkey->save_parameters; 11525b3c049e70834cf33790a28643ab058b507b35cBen Cheng 11625b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (mode >= 0) 11725b3c049e70834cf33790a28643ab058b507b35cBen Cheng pkey->save_parameters = mode; 11825b3c049e70834cf33790a28643ab058b507b35cBen Cheng return(ret); 11925b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 12025b3c049e70834cf33790a28643ab058b507b35cBen Cheng#endif 12125b3c049e70834cf33790a28643ab058b507b35cBen Cheng return(0); 12225b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 12325b3c049e70834cf33790a28643ab058b507b35cBen Cheng 12425b3c049e70834cf33790a28643ab058b507b35cBen Chengint EVP_PKEY_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from) 12525b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 12625b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (to->type != from->type) 12725b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 12825b3c049e70834cf33790a28643ab058b507b35cBen Cheng EVPerr(EVP_F_EVP_PKEY_COPY_PARAMETERS,EVP_R_DIFFERENT_KEY_TYPES); 12925b3c049e70834cf33790a28643ab058b507b35cBen Cheng goto err; 13025b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 13125b3c049e70834cf33790a28643ab058b507b35cBen Cheng 13225b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (EVP_PKEY_missing_parameters(from)) 13325b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 13425b3c049e70834cf33790a28643ab058b507b35cBen Cheng EVPerr(EVP_F_EVP_PKEY_COPY_PARAMETERS,EVP_R_MISSING_PARAMETERS); 13525b3c049e70834cf33790a28643ab058b507b35cBen Cheng goto err; 13625b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 13725b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (from->ameth && from->ameth->param_copy) 13825b3c049e70834cf33790a28643ab058b507b35cBen Cheng return from->ameth->param_copy(to, from); 13925b3c049e70834cf33790a28643ab058b507b35cBen Chengerr: 14025b3c049e70834cf33790a28643ab058b507b35cBen Cheng return 0; 14125b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 14225b3c049e70834cf33790a28643ab058b507b35cBen Cheng 14325b3c049e70834cf33790a28643ab058b507b35cBen Chengint EVP_PKEY_missing_parameters(const EVP_PKEY *pkey) 14425b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 14525b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (pkey->ameth && pkey->ameth->param_missing) 14625b3c049e70834cf33790a28643ab058b507b35cBen Cheng return pkey->ameth->param_missing(pkey); 14725b3c049e70834cf33790a28643ab058b507b35cBen Cheng return 0; 14825b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 14925b3c049e70834cf33790a28643ab058b507b35cBen Cheng 15025b3c049e70834cf33790a28643ab058b507b35cBen Chengint EVP_PKEY_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b) 15125b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 15225b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (a->type != b->type) 15325b3c049e70834cf33790a28643ab058b507b35cBen Cheng return -1; 15425b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (a->ameth && a->ameth->param_cmp) 15525b3c049e70834cf33790a28643ab058b507b35cBen Cheng return a->ameth->param_cmp(a, b); 15625b3c049e70834cf33790a28643ab058b507b35cBen Cheng return -2; 15725b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 15825b3c049e70834cf33790a28643ab058b507b35cBen Cheng 15925b3c049e70834cf33790a28643ab058b507b35cBen Chengint EVP_PKEY_cmp(const EVP_PKEY *a, const EVP_PKEY *b) 16025b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 16125b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (a->type != b->type) 16225b3c049e70834cf33790a28643ab058b507b35cBen Cheng return -1; 16325b3c049e70834cf33790a28643ab058b507b35cBen Cheng 16425b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (a->ameth) 16525b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 16625b3c049e70834cf33790a28643ab058b507b35cBen Cheng int ret; 16725b3c049e70834cf33790a28643ab058b507b35cBen Cheng /* Compare parameters if the algorithm has them */ 16825b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (a->ameth->param_cmp) 16925b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 17025b3c049e70834cf33790a28643ab058b507b35cBen Cheng ret = a->ameth->param_cmp(a, b); 17125b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (ret <= 0) 17225b3c049e70834cf33790a28643ab058b507b35cBen Cheng return ret; 17325b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 17425b3c049e70834cf33790a28643ab058b507b35cBen Cheng 17525b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (a->ameth->pub_cmp) 17625b3c049e70834cf33790a28643ab058b507b35cBen Cheng return a->ameth->pub_cmp(a, b); 17725b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 17825b3c049e70834cf33790a28643ab058b507b35cBen Cheng 17925b3c049e70834cf33790a28643ab058b507b35cBen Cheng return -2; 18025b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 18125b3c049e70834cf33790a28643ab058b507b35cBen Cheng 18225b3c049e70834cf33790a28643ab058b507b35cBen ChengEVP_PKEY *EVP_PKEY_new(void) 18325b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 18425b3c049e70834cf33790a28643ab058b507b35cBen Cheng EVP_PKEY *ret; 18525b3c049e70834cf33790a28643ab058b507b35cBen Cheng 18625b3c049e70834cf33790a28643ab058b507b35cBen Cheng ret=(EVP_PKEY *)OPENSSL_malloc(sizeof(EVP_PKEY)); 18725b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (ret == NULL) 18825b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 18925b3c049e70834cf33790a28643ab058b507b35cBen Cheng EVPerr(EVP_F_EVP_PKEY_NEW,ERR_R_MALLOC_FAILURE); 19025b3c049e70834cf33790a28643ab058b507b35cBen Cheng return(NULL); 19125b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 19225b3c049e70834cf33790a28643ab058b507b35cBen Cheng ret->type=EVP_PKEY_NONE; 19325b3c049e70834cf33790a28643ab058b507b35cBen Cheng ret->save_type=EVP_PKEY_NONE; 19425b3c049e70834cf33790a28643ab058b507b35cBen Cheng ret->references=1; 19525b3c049e70834cf33790a28643ab058b507b35cBen Cheng ret->ameth=NULL; 19625b3c049e70834cf33790a28643ab058b507b35cBen Cheng ret->engine=NULL; 19725b3c049e70834cf33790a28643ab058b507b35cBen Cheng ret->pkey.ptr=NULL; 19825b3c049e70834cf33790a28643ab058b507b35cBen Cheng ret->attributes=NULL; 19925b3c049e70834cf33790a28643ab058b507b35cBen Cheng ret->save_parameters=1; 20025b3c049e70834cf33790a28643ab058b507b35cBen Cheng return(ret); 20125b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 20225b3c049e70834cf33790a28643ab058b507b35cBen Cheng 20325b3c049e70834cf33790a28643ab058b507b35cBen ChengEVP_PKEY *EVP_PKEY_dup(EVP_PKEY *pkey) 20425b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 20525b3c049e70834cf33790a28643ab058b507b35cBen Cheng CRYPTO_add(&pkey->references,1,CRYPTO_LOCK_EVP_PKEY); 20625b3c049e70834cf33790a28643ab058b507b35cBen Cheng return pkey; 20725b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 20825b3c049e70834cf33790a28643ab058b507b35cBen Cheng 20925b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Setup a public key ASN1 method and ENGINE from a NID or a string. 21025b3c049e70834cf33790a28643ab058b507b35cBen Cheng * If pkey is NULL just return 1 or 0 if the algorithm exists. 21125b3c049e70834cf33790a28643ab058b507b35cBen Cheng */ 21225b3c049e70834cf33790a28643ab058b507b35cBen Cheng 21325b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic int pkey_set_type(EVP_PKEY *pkey, int type, const char *str, int len) 21425b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 21525b3c049e70834cf33790a28643ab058b507b35cBen Cheng const EVP_PKEY_ASN1_METHOD *ameth; 21625b3c049e70834cf33790a28643ab058b507b35cBen Cheng ENGINE *e = NULL; 21725b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (pkey) 21825b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 21925b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (pkey->pkey.ptr) 22025b3c049e70834cf33790a28643ab058b507b35cBen Cheng EVP_PKEY_free_it(pkey); 22125b3c049e70834cf33790a28643ab058b507b35cBen Cheng /* If key type matches and a method exists then this 22225b3c049e70834cf33790a28643ab058b507b35cBen Cheng * lookup has succeeded once so just indicate success. 22325b3c049e70834cf33790a28643ab058b507b35cBen Cheng */ 22425b3c049e70834cf33790a28643ab058b507b35cBen Cheng if ((type == pkey->save_type) && pkey->ameth) 22525b3c049e70834cf33790a28643ab058b507b35cBen Cheng return 1; 22625b3c049e70834cf33790a28643ab058b507b35cBen Cheng#ifndef OPENSSL_NO_ENGINE 22725b3c049e70834cf33790a28643ab058b507b35cBen Cheng /* If we have an ENGINE release it */ 22825b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (pkey->engine) 22925b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 23025b3c049e70834cf33790a28643ab058b507b35cBen Cheng ENGINE_finish(pkey->engine); 23125b3c049e70834cf33790a28643ab058b507b35cBen Cheng pkey->engine = NULL; 23225b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 23325b3c049e70834cf33790a28643ab058b507b35cBen Cheng#endif 23425b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 23525b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (str) 23625b3c049e70834cf33790a28643ab058b507b35cBen Cheng ameth = EVP_PKEY_asn1_find_str(&e, str, len); 23725b3c049e70834cf33790a28643ab058b507b35cBen Cheng else 23825b3c049e70834cf33790a28643ab058b507b35cBen Cheng ameth = EVP_PKEY_asn1_find(&e, type); 23925b3c049e70834cf33790a28643ab058b507b35cBen Cheng#ifndef OPENSSL_NO_ENGINE 24025b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (!pkey && e) 24125b3c049e70834cf33790a28643ab058b507b35cBen Cheng ENGINE_finish(e); 24225b3c049e70834cf33790a28643ab058b507b35cBen Cheng#endif 24325b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (!ameth) 24425b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 24525b3c049e70834cf33790a28643ab058b507b35cBen Cheng EVPerr(EVP_F_PKEY_SET_TYPE, EVP_R_UNSUPPORTED_ALGORITHM); 24625b3c049e70834cf33790a28643ab058b507b35cBen Cheng return 0; 24725b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 24825b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (pkey) 24925b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 25025b3c049e70834cf33790a28643ab058b507b35cBen Cheng pkey->ameth = ameth; 25125b3c049e70834cf33790a28643ab058b507b35cBen Cheng pkey->engine = e; 25225b3c049e70834cf33790a28643ab058b507b35cBen Cheng 25325b3c049e70834cf33790a28643ab058b507b35cBen Cheng pkey->type = pkey->ameth->pkey_id; 25425b3c049e70834cf33790a28643ab058b507b35cBen Cheng pkey->save_type=type; 25525b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 25625b3c049e70834cf33790a28643ab058b507b35cBen Cheng return 1; 25725b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 25825b3c049e70834cf33790a28643ab058b507b35cBen Cheng 25925b3c049e70834cf33790a28643ab058b507b35cBen Chengint EVP_PKEY_set_type(EVP_PKEY *pkey, int type) 26025b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 26125b3c049e70834cf33790a28643ab058b507b35cBen Cheng return pkey_set_type(pkey, type, NULL, -1); 26225b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 26325b3c049e70834cf33790a28643ab058b507b35cBen Cheng 26425b3c049e70834cf33790a28643ab058b507b35cBen Chengint EVP_PKEY_set_type_str(EVP_PKEY *pkey, const char *str, int len) 26525b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 26625b3c049e70834cf33790a28643ab058b507b35cBen Cheng return pkey_set_type(pkey, EVP_PKEY_NONE, str, len); 26725b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 26825b3c049e70834cf33790a28643ab058b507b35cBen Cheng 26925b3c049e70834cf33790a28643ab058b507b35cBen Chengint EVP_PKEY_assign(EVP_PKEY *pkey, int type, void *key) 27025b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 27125b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (!EVP_PKEY_set_type(pkey, type)) 27225b3c049e70834cf33790a28643ab058b507b35cBen Cheng return 0; 27325b3c049e70834cf33790a28643ab058b507b35cBen Cheng pkey->pkey.ptr=key; 27425b3c049e70834cf33790a28643ab058b507b35cBen Cheng return (key != NULL); 27525b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 27625b3c049e70834cf33790a28643ab058b507b35cBen Cheng 27725b3c049e70834cf33790a28643ab058b507b35cBen Chengvoid *EVP_PKEY_get0(EVP_PKEY *pkey) 27825b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 27925b3c049e70834cf33790a28643ab058b507b35cBen Cheng return pkey->pkey.ptr; 28025b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 28125b3c049e70834cf33790a28643ab058b507b35cBen Cheng 28225b3c049e70834cf33790a28643ab058b507b35cBen Cheng#ifndef OPENSSL_NO_RSA 28325b3c049e70834cf33790a28643ab058b507b35cBen Chengint EVP_PKEY_set1_RSA(EVP_PKEY *pkey, RSA *key) 28425b3c049e70834cf33790a28643ab058b507b35cBen Cheng{ 28525b3c049e70834cf33790a28643ab058b507b35cBen Cheng int ret = EVP_PKEY_assign_RSA(pkey, key); 28625b3c049e70834cf33790a28643ab058b507b35cBen Cheng if(ret) 28725b3c049e70834cf33790a28643ab058b507b35cBen Cheng RSA_up_ref(key); 28825b3c049e70834cf33790a28643ab058b507b35cBen Cheng return ret; 28925b3c049e70834cf33790a28643ab058b507b35cBen Cheng} 29025b3c049e70834cf33790a28643ab058b507b35cBen Cheng 29125b3c049e70834cf33790a28643ab058b507b35cBen ChengRSA *EVP_PKEY_get1_RSA(EVP_PKEY *pkey) 29225b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 29325b3c049e70834cf33790a28643ab058b507b35cBen Cheng if(pkey->type != EVP_PKEY_RSA) { 29425b3c049e70834cf33790a28643ab058b507b35cBen Cheng EVPerr(EVP_F_EVP_PKEY_GET1_RSA, EVP_R_EXPECTING_AN_RSA_KEY); 29525b3c049e70834cf33790a28643ab058b507b35cBen Cheng return NULL; 29625b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 29725b3c049e70834cf33790a28643ab058b507b35cBen Cheng RSA_up_ref(pkey->pkey.rsa); 29825b3c049e70834cf33790a28643ab058b507b35cBen Cheng return pkey->pkey.rsa; 29925b3c049e70834cf33790a28643ab058b507b35cBen Cheng} 30025b3c049e70834cf33790a28643ab058b507b35cBen Cheng#endif 30125b3c049e70834cf33790a28643ab058b507b35cBen Cheng 30225b3c049e70834cf33790a28643ab058b507b35cBen Cheng#ifndef OPENSSL_NO_DSA 30325b3c049e70834cf33790a28643ab058b507b35cBen Chengint EVP_PKEY_set1_DSA(EVP_PKEY *pkey, DSA *key) 30425b3c049e70834cf33790a28643ab058b507b35cBen Cheng{ 30525b3c049e70834cf33790a28643ab058b507b35cBen Cheng int ret = EVP_PKEY_assign_DSA(pkey, key); 30625b3c049e70834cf33790a28643ab058b507b35cBen Cheng if(ret) 30725b3c049e70834cf33790a28643ab058b507b35cBen Cheng DSA_up_ref(key); 30825b3c049e70834cf33790a28643ab058b507b35cBen Cheng return ret; 30925b3c049e70834cf33790a28643ab058b507b35cBen Cheng} 31025b3c049e70834cf33790a28643ab058b507b35cBen Cheng 31125b3c049e70834cf33790a28643ab058b507b35cBen ChengDSA *EVP_PKEY_get1_DSA(EVP_PKEY *pkey) 31225b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 31325b3c049e70834cf33790a28643ab058b507b35cBen Cheng if(pkey->type != EVP_PKEY_DSA) { 31425b3c049e70834cf33790a28643ab058b507b35cBen Cheng EVPerr(EVP_F_EVP_PKEY_GET1_DSA, EVP_R_EXPECTING_A_DSA_KEY); 31525b3c049e70834cf33790a28643ab058b507b35cBen Cheng return NULL; 31625b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 31725b3c049e70834cf33790a28643ab058b507b35cBen Cheng DSA_up_ref(pkey->pkey.dsa); 31825b3c049e70834cf33790a28643ab058b507b35cBen Cheng return pkey->pkey.dsa; 31925b3c049e70834cf33790a28643ab058b507b35cBen Cheng} 32025b3c049e70834cf33790a28643ab058b507b35cBen Cheng#endif 32125b3c049e70834cf33790a28643ab058b507b35cBen Cheng 32225b3c049e70834cf33790a28643ab058b507b35cBen Cheng#ifndef OPENSSL_NO_EC 32325b3c049e70834cf33790a28643ab058b507b35cBen Cheng 32425b3c049e70834cf33790a28643ab058b507b35cBen Chengint EVP_PKEY_set1_EC_KEY(EVP_PKEY *pkey, EC_KEY *key) 32525b3c049e70834cf33790a28643ab058b507b35cBen Cheng{ 32625b3c049e70834cf33790a28643ab058b507b35cBen Cheng int ret = EVP_PKEY_assign_EC_KEY(pkey,key); 32725b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (ret) 32825b3c049e70834cf33790a28643ab058b507b35cBen Cheng EC_KEY_up_ref(key); 32925b3c049e70834cf33790a28643ab058b507b35cBen Cheng return ret; 33025b3c049e70834cf33790a28643ab058b507b35cBen Cheng} 33125b3c049e70834cf33790a28643ab058b507b35cBen Cheng 33225b3c049e70834cf33790a28643ab058b507b35cBen ChengEC_KEY *EVP_PKEY_get1_EC_KEY(EVP_PKEY *pkey) 33325b3c049e70834cf33790a28643ab058b507b35cBen Cheng{ 33425b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (pkey->type != EVP_PKEY_EC) 33525b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 33625b3c049e70834cf33790a28643ab058b507b35cBen Cheng EVPerr(EVP_F_EVP_PKEY_GET1_EC_KEY, EVP_R_EXPECTING_A_EC_KEY); 33725b3c049e70834cf33790a28643ab058b507b35cBen Cheng return NULL; 33825b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 33925b3c049e70834cf33790a28643ab058b507b35cBen Cheng EC_KEY_up_ref(pkey->pkey.ec); 34025b3c049e70834cf33790a28643ab058b507b35cBen Cheng return pkey->pkey.ec; 34125b3c049e70834cf33790a28643ab058b507b35cBen Cheng} 34225b3c049e70834cf33790a28643ab058b507b35cBen Cheng#endif 34325b3c049e70834cf33790a28643ab058b507b35cBen Cheng 34425b3c049e70834cf33790a28643ab058b507b35cBen Cheng 34525b3c049e70834cf33790a28643ab058b507b35cBen Cheng#ifndef OPENSSL_NO_DH 34625b3c049e70834cf33790a28643ab058b507b35cBen Cheng 34725b3c049e70834cf33790a28643ab058b507b35cBen Chengint EVP_PKEY_set1_DH(EVP_PKEY *pkey, DH *key) 34825b3c049e70834cf33790a28643ab058b507b35cBen Cheng{ 34925b3c049e70834cf33790a28643ab058b507b35cBen Cheng int ret = EVP_PKEY_assign_DH(pkey, key); 35025b3c049e70834cf33790a28643ab058b507b35cBen Cheng if(ret) 35125b3c049e70834cf33790a28643ab058b507b35cBen Cheng DH_up_ref(key); 35225b3c049e70834cf33790a28643ab058b507b35cBen Cheng return ret; 35325b3c049e70834cf33790a28643ab058b507b35cBen Cheng} 35425b3c049e70834cf33790a28643ab058b507b35cBen Cheng 35525b3c049e70834cf33790a28643ab058b507b35cBen ChengDH *EVP_PKEY_get1_DH(EVP_PKEY *pkey) 35625b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 35725b3c049e70834cf33790a28643ab058b507b35cBen Cheng if(pkey->type != EVP_PKEY_DH) { 35825b3c049e70834cf33790a28643ab058b507b35cBen Cheng EVPerr(EVP_F_EVP_PKEY_GET1_DH, EVP_R_EXPECTING_A_DH_KEY); 35925b3c049e70834cf33790a28643ab058b507b35cBen Cheng return NULL; 36025b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 36125b3c049e70834cf33790a28643ab058b507b35cBen Cheng DH_up_ref(pkey->pkey.dh); 36225b3c049e70834cf33790a28643ab058b507b35cBen Cheng return pkey->pkey.dh; 36325b3c049e70834cf33790a28643ab058b507b35cBen Cheng} 36425b3c049e70834cf33790a28643ab058b507b35cBen Cheng#endif 36525b3c049e70834cf33790a28643ab058b507b35cBen Cheng 36625b3c049e70834cf33790a28643ab058b507b35cBen Chengint EVP_PKEY_type(int type) 36725b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 36825b3c049e70834cf33790a28643ab058b507b35cBen Cheng int ret; 36925b3c049e70834cf33790a28643ab058b507b35cBen Cheng const EVP_PKEY_ASN1_METHOD *ameth; 37025b3c049e70834cf33790a28643ab058b507b35cBen Cheng ENGINE *e; 37125b3c049e70834cf33790a28643ab058b507b35cBen Cheng ameth = EVP_PKEY_asn1_find(&e, type); 37225b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (ameth) 37325b3c049e70834cf33790a28643ab058b507b35cBen Cheng ret = ameth->pkey_id; 37425b3c049e70834cf33790a28643ab058b507b35cBen Cheng else 37525b3c049e70834cf33790a28643ab058b507b35cBen Cheng ret = NID_undef; 37625b3c049e70834cf33790a28643ab058b507b35cBen Cheng#ifndef OPENSSL_NO_ENGINE 37725b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (e) 37825b3c049e70834cf33790a28643ab058b507b35cBen Cheng ENGINE_finish(e); 37925b3c049e70834cf33790a28643ab058b507b35cBen Cheng#endif 38025b3c049e70834cf33790a28643ab058b507b35cBen Cheng return ret; 38125b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 38225b3c049e70834cf33790a28643ab058b507b35cBen Cheng 38325b3c049e70834cf33790a28643ab058b507b35cBen Chengint EVP_PKEY_id(const EVP_PKEY *pkey) 38425b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 38525b3c049e70834cf33790a28643ab058b507b35cBen Cheng return pkey->type; 38625b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 38725b3c049e70834cf33790a28643ab058b507b35cBen Cheng 38825b3c049e70834cf33790a28643ab058b507b35cBen Chengint EVP_PKEY_base_id(const EVP_PKEY *pkey) 38925b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 39025b3c049e70834cf33790a28643ab058b507b35cBen Cheng return EVP_PKEY_type(pkey->type); 39125b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 39225b3c049e70834cf33790a28643ab058b507b35cBen Cheng 39325b3c049e70834cf33790a28643ab058b507b35cBen Chengvoid EVP_PKEY_free(EVP_PKEY *x) 39425b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 39525b3c049e70834cf33790a28643ab058b507b35cBen Cheng int i; 39625b3c049e70834cf33790a28643ab058b507b35cBen Cheng 39725b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (x == NULL) return; 39825b3c049e70834cf33790a28643ab058b507b35cBen Cheng 39925b3c049e70834cf33790a28643ab058b507b35cBen Cheng i=CRYPTO_add(&x->references,-1,CRYPTO_LOCK_EVP_PKEY); 40025b3c049e70834cf33790a28643ab058b507b35cBen Cheng#ifdef REF_PRINT 40125b3c049e70834cf33790a28643ab058b507b35cBen Cheng REF_PRINT("EVP_PKEY",x); 40225b3c049e70834cf33790a28643ab058b507b35cBen Cheng#endif 40325b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (i > 0) return; 40425b3c049e70834cf33790a28643ab058b507b35cBen Cheng#ifdef REF_CHECK 40525b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (i < 0) 40625b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 40725b3c049e70834cf33790a28643ab058b507b35cBen Cheng fprintf(stderr,"EVP_PKEY_free, bad reference count\n"); 40825b3c049e70834cf33790a28643ab058b507b35cBen Cheng abort(); 40925b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 41025b3c049e70834cf33790a28643ab058b507b35cBen Cheng#endif 41125b3c049e70834cf33790a28643ab058b507b35cBen Cheng EVP_PKEY_free_it(x); 41225b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (x->attributes) 41325b3c049e70834cf33790a28643ab058b507b35cBen Cheng sk_X509_ATTRIBUTE_pop_free(x->attributes, X509_ATTRIBUTE_free); 41425b3c049e70834cf33790a28643ab058b507b35cBen Cheng OPENSSL_free(x); 41525b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 41625b3c049e70834cf33790a28643ab058b507b35cBen Cheng 41725b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic void EVP_PKEY_free_it(EVP_PKEY *x) 41825b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 41925b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (x->ameth && x->ameth->pkey_free) 42025b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 42125b3c049e70834cf33790a28643ab058b507b35cBen Cheng x->ameth->pkey_free(x); 42225b3c049e70834cf33790a28643ab058b507b35cBen Cheng x->pkey.ptr = NULL; 42325b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 42425b3c049e70834cf33790a28643ab058b507b35cBen Cheng#ifndef OPENSSL_NO_ENGINE 42525b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (x->engine) 42625b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 42725b3c049e70834cf33790a28643ab058b507b35cBen Cheng ENGINE_finish(x->engine); 42825b3c049e70834cf33790a28643ab058b507b35cBen Cheng x->engine = NULL; 42925b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 43025b3c049e70834cf33790a28643ab058b507b35cBen Cheng#endif 43125b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 43225b3c049e70834cf33790a28643ab058b507b35cBen Cheng 43325b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic int unsup_alg(BIO *out, const EVP_PKEY *pkey, int indent, 43425b3c049e70834cf33790a28643ab058b507b35cBen Cheng const char *kstr) 43525b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 43625b3c049e70834cf33790a28643ab058b507b35cBen Cheng BIO_indent(out, indent, 128); 43725b3c049e70834cf33790a28643ab058b507b35cBen Cheng BIO_printf(out, "%s algorithm \"%s\" unsupported\n", 43825b3c049e70834cf33790a28643ab058b507b35cBen Cheng kstr, OBJ_nid2ln(pkey->type)); 43925b3c049e70834cf33790a28643ab058b507b35cBen Cheng return 1; 44025b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 44125b3c049e70834cf33790a28643ab058b507b35cBen Cheng 44225b3c049e70834cf33790a28643ab058b507b35cBen Chengint EVP_PKEY_print_public(BIO *out, const EVP_PKEY *pkey, 44325b3c049e70834cf33790a28643ab058b507b35cBen Cheng int indent, ASN1_PCTX *pctx) 44425b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 44525b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (pkey->ameth && pkey->ameth->pub_print) 44625b3c049e70834cf33790a28643ab058b507b35cBen Cheng return pkey->ameth->pub_print(out, pkey, indent, pctx); 44725b3c049e70834cf33790a28643ab058b507b35cBen Cheng 44825b3c049e70834cf33790a28643ab058b507b35cBen Cheng return unsup_alg(out, pkey, indent, "Public Key"); 44925b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 45025b3c049e70834cf33790a28643ab058b507b35cBen Cheng 45125b3c049e70834cf33790a28643ab058b507b35cBen Chengint EVP_PKEY_print_private(BIO *out, const EVP_PKEY *pkey, 45225b3c049e70834cf33790a28643ab058b507b35cBen Cheng int indent, ASN1_PCTX *pctx) 45325b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 45425b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (pkey->ameth && pkey->ameth->priv_print) 45525b3c049e70834cf33790a28643ab058b507b35cBen Cheng return pkey->ameth->priv_print(out, pkey, indent, pctx); 45625b3c049e70834cf33790a28643ab058b507b35cBen Cheng 45725b3c049e70834cf33790a28643ab058b507b35cBen Cheng return unsup_alg(out, pkey, indent, "Private Key"); 45825b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 45925b3c049e70834cf33790a28643ab058b507b35cBen Cheng 46025b3c049e70834cf33790a28643ab058b507b35cBen Chengint EVP_PKEY_print_params(BIO *out, const EVP_PKEY *pkey, 46125b3c049e70834cf33790a28643ab058b507b35cBen Cheng int indent, ASN1_PCTX *pctx) 46225b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 46325b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (pkey->ameth && pkey->ameth->param_print) 46425b3c049e70834cf33790a28643ab058b507b35cBen Cheng return pkey->ameth->param_print(out, pkey, indent, pctx); 46525b3c049e70834cf33790a28643ab058b507b35cBen Cheng return unsup_alg(out, pkey, indent, "Parameters"); 46625b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 46725b3c049e70834cf33790a28643ab058b507b35cBen Cheng 46825b3c049e70834cf33790a28643ab058b507b35cBen Chengint EVP_PKEY_get_default_digest_nid(EVP_PKEY *pkey, int *pnid) 46925b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 47025b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (!pkey->ameth || !pkey->ameth->pkey_ctrl) 47125b3c049e70834cf33790a28643ab058b507b35cBen Cheng return -2; 47225b3c049e70834cf33790a28643ab058b507b35cBen Cheng return pkey->ameth->pkey_ctrl(pkey, ASN1_PKEY_CTRL_DEFAULT_MD_NID, 47325b3c049e70834cf33790a28643ab058b507b35cBen Cheng 0, pnid); 47425b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 47525b3c049e70834cf33790a28643ab058b507b35cBen Cheng 47625b3c049e70834cf33790a28643ab058b507b35cBen Cheng