summaryrefslogtreecommitdiffstats
path: root/crypto
diff options
context:
space:
mode:
authorMatt Caswell <matt@openssl.org>2018-03-05 14:06:41 +0000
committerMatt Caswell <matt@openssl.org>2018-03-15 12:47:27 +0000
commita08802ce296a90d8cf9032987b0dac959ccf00ad (patch)
tree25dba98c7dbf1e46afdaeeec5348016045485e20 /crypto
parent9e381e8a018592a2a42e83df402e1ef921469e9f (diff)
Add functions to create an EVP_PKEY from raw private/public key data
Not all algorithms will support this, since their keys are not a simple block of data. But many can. Reviewed-by: Richard Levitte <levitte@openssl.org> (Merged from https://github.com/openssl/openssl/pull/5520)
Diffstat (limited to 'crypto')
-rw-r--r--crypto/err/openssl.txt2
-rw-r--r--crypto/evp/evp_err.c4
-rw-r--r--crypto/evp/p_lib.c75
-rw-r--r--crypto/include/internal/asn1_int.h3
4 files changed, 77 insertions, 7 deletions
diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt
index 3f6169ee1c..f33e9612c0 100644
--- a/crypto/err/openssl.txt
+++ b/crypto/err/openssl.txt
@@ -703,6 +703,8 @@ EVP_F_EVP_PKEY_GET0_SIPHASH:172:EVP_PKEY_get0_siphash
EVP_F_EVP_PKEY_KEYGEN:146:EVP_PKEY_keygen
EVP_F_EVP_PKEY_KEYGEN_INIT:147:EVP_PKEY_keygen_init
EVP_F_EVP_PKEY_NEW:106:EVP_PKEY_new
+EVP_F_EVP_PKEY_NEW_PRIVATE_KEY:191:EVP_PKEY_new_private_key
+EVP_F_EVP_PKEY_NEW_PUBLIC_KEY:192:EVP_PKEY_new_public_key
EVP_F_EVP_PKEY_PARAMGEN:148:EVP_PKEY_paramgen
EVP_F_EVP_PKEY_PARAMGEN_INIT:149:EVP_PKEY_paramgen_init
EVP_F_EVP_PKEY_PARAM_CHECK:189:EVP_PKEY_param_check
diff --git a/crypto/evp/evp_err.c b/crypto/evp/evp_err.c
index a43de74605..d45f2b96b1 100644
--- a/crypto/evp/evp_err.c
+++ b/crypto/evp/evp_err.c
@@ -93,6 +93,10 @@ static const ERR_STRING_DATA EVP_str_functs[] = {
{ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_KEYGEN_INIT, 0),
"EVP_PKEY_keygen_init"},
{ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_NEW, 0), "EVP_PKEY_new"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_NEW_PRIVATE_KEY, 0),
+ "EVP_PKEY_new_private_key"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_NEW_PUBLIC_KEY, 0),
+ "EVP_PKEY_new_public_key"},
{ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_PARAMGEN, 0), "EVP_PKEY_paramgen"},
{ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_PARAMGEN_INIT, 0),
"EVP_PKEY_paramgen_init"},
diff --git a/crypto/evp/p_lib.c b/crypto/evp/p_lib.c
index 6177e04483..7ec1dd7800 100644
--- a/crypto/evp/p_lib.c
+++ b/crypto/evp/p_lib.c
@@ -174,10 +174,12 @@ int EVP_PKEY_up_ref(EVP_PKEY *pkey)
* is NULL just return 1 or 0 if the algorithm exists.
*/
-static int pkey_set_type(EVP_PKEY *pkey, int type, const char *str, int len)
+static int pkey_set_type(EVP_PKEY *pkey, ENGINE *e, int type, const char *str,
+ int len)
{
const EVP_PKEY_ASN1_METHOD *ameth;
- ENGINE *e = NULL;
+ ENGINE **eptr = (e == NULL) ? &e : NULL;
+
if (pkey) {
if (pkey->pkey.ptr)
EVP_PKEY_free_it(pkey);
@@ -196,11 +198,11 @@ static int pkey_set_type(EVP_PKEY *pkey, int type, const char *str, int len)
#endif
}
if (str)
- ameth = EVP_PKEY_asn1_find_str(&e, str, len);
+ ameth = EVP_PKEY_asn1_find_str(eptr, str, len);
else
- ameth = EVP_PKEY_asn1_find(&e, type);
+ ameth = EVP_PKEY_asn1_find(eptr, type);
#ifndef OPENSSL_NO_ENGINE
- if (pkey == NULL)
+ if (pkey == NULL && eptr != NULL)
ENGINE_finish(e);
#endif
if (ameth == NULL) {
@@ -217,14 +219,73 @@ static int pkey_set_type(EVP_PKEY *pkey, int type, const char *str, int len)
return 1;
}
+EVP_PKEY *EVP_PKEY_new_private_key(int type, ENGINE *e, unsigned char *priv,
+ size_t len)
+{
+ EVP_PKEY *ret = EVP_PKEY_new();
+
+ if (ret == NULL
+ || !pkey_set_type(ret, e, type, NULL, -1)) {
+ /* EVPerr already called */
+ goto err;
+ }
+
+ if (ret->ameth->set_priv_key == NULL) {
+ EVPerr(EVP_F_EVP_PKEY_NEW_PRIVATE_KEY,
+ EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+ goto err;
+ }
+
+ if (!ret->ameth->set_priv_key(ret, priv, len)) {
+ /* We assume the method function calls EVPerr */
+ goto err;
+ }
+
+ return ret;
+
+ err:
+ EVP_PKEY_free(ret);
+ return NULL;
+}
+
+EVP_PKEY *EVP_PKEY_new_public_key(int type, ENGINE *e, unsigned char *pub,
+ size_t len)
+{
+ EVP_PKEY *ret = EVP_PKEY_new();
+
+ if (ret == NULL
+ || !pkey_set_type(ret, e, type, NULL, -1)) {
+ /* EVPerr already called */
+ goto err;
+ }
+
+ if (ret->ameth->set_pub_key == NULL) {
+ EVPerr(EVP_F_EVP_PKEY_NEW_PUBLIC_KEY,
+ EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+ goto err;
+ }
+
+ if (!ret->ameth->set_pub_key(ret, pub, len)) {
+ /* We assume the method function calls EVPerr */
+ goto err;
+ }
+
+ return ret;
+
+ err:
+ EVP_PKEY_free(ret);
+ return NULL;
+}
+
+
int EVP_PKEY_set_type(EVP_PKEY *pkey, int type)
{
- return pkey_set_type(pkey, type, NULL, -1);
+ return pkey_set_type(pkey, NULL, type, NULL, -1);
}
int EVP_PKEY_set_type_str(EVP_PKEY *pkey, const char *str, int len)
{
- return pkey_set_type(pkey, EVP_PKEY_NONE, str, len);
+ return pkey_set_type(pkey, NULL, EVP_PKEY_NONE, str, len);
}
#ifndef OPENSSL_NO_ENGINE
int EVP_PKEY_set1_engine(EVP_PKEY *pkey, ENGINE *e)
diff --git a/crypto/include/internal/asn1_int.h b/crypto/include/internal/asn1_int.h
index 664d4d69cb..90673ab3fe 100644
--- a/crypto/include/internal/asn1_int.h
+++ b/crypto/include/internal/asn1_int.h
@@ -58,6 +58,9 @@ struct evp_pkey_asn1_method_st {
int (*pkey_check) (const EVP_PKEY *pk);
int (*pkey_public_check) (const EVP_PKEY *pk);
int (*pkey_param_check) (const EVP_PKEY *pk);
+ /* Get/set raw private/public key data */
+ int (*set_priv_key) (EVP_PKEY *pk, const unsigned char *priv, size_t len);
+ int (*set_pub_key) (EVP_PKEY *pk, const unsigned char *pub, size_t len);
} /* EVP_PKEY_ASN1_METHOD */ ;
DEFINE_STACK_OF_CONST(EVP_PKEY_ASN1_METHOD)