chore: checkpoint before Python removal

This commit is contained in:
2026-03-26 22:33:59 +00:00
parent 683cec9307
commit e568ddf82a
29972 changed files with 11269302 additions and 2 deletions

View File

@@ -0,0 +1,727 @@
// Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) All rights reserved.
// SPDX-License-Identifier: Apache-2.0
#include <openssl/evp.h>
#include <string.h>
#include <openssl/bytestring.h>
#include <openssl/dh.h>
#include <openssl/dsa.h>
#include <openssl/ec_key.h>
#include <openssl/err.h>
#include <openssl/rsa.h>
#include "../bytestring/internal.h"
#include "../fipsmodule/dh/internal.h"
#include "../fipsmodule/evp/internal.h"
#include "../fipsmodule/pqdsa/internal.h"
#include "../internal.h"
#include "internal.h"
#include "../fipsmodule/kem/internal.h"
// parse_key_type takes the algorithm cbs sequence |cbs| and extracts the OID.
// The extracted OID will be set on |out_oid| so that it may be used later in
// specific key type implementations like PQDSA.
// The OID is then searched against ASN.1 methods for a method with that OID.
// As the |OID| is read from |cbs| the buffer is advanced.
// For the case of |NID_rsa| the method |rsa_asn1_meth| is returned.
// For the case of |EVP_PKEY_PQDSA| the method |pqdsa_asn1.meth| is returned.
// For the case of |EVP_PKEY_KEM| the method |kem_asn1.meth| is returned.
static const EVP_PKEY_ASN1_METHOD *parse_key_type(CBS *cbs, CBS *out_oid) {
CBS oid;
if (!CBS_get_asn1(cbs, &oid, CBS_ASN1_OBJECT)) {
return NULL;
}
CBS_init(out_oid, CBS_data(&oid), CBS_len(&oid));
const EVP_PKEY_ASN1_METHOD *const *asn1_methods =
AWSLC_non_fips_pkey_evp_asn1_methods();
for (size_t i = 0; i < ASN1_EVP_PKEY_METHODS; i++) {
const EVP_PKEY_ASN1_METHOD *method = asn1_methods[i];
if (CBS_len(&oid) == method->oid_len &&
OPENSSL_memcmp(CBS_data(&oid), method->oid, method->oid_len) == 0) {
return method;
}
}
// Special logic to handle the rarer |NID_rsa|.
// https://www.itu.int/ITU-T/formal-language/itu-t/x/x509/2008/AlgorithmObjectIdentifiers.html
if (OBJ_cbs2nid(&oid) == NID_rsa) {
return &rsa_asn1_meth;
}
// The pkey_id for the pqdsa_asn1_meth is EVP_PKEY_PQDSA, as this holds all
// asn1 functions for pqdsa types. However, the incoming CBS has the OID for
// the specific algorithm. So we must search explicitly for the algorithm.
const EVP_PKEY_ASN1_METHOD *pqdsa_method = PQDSA_find_asn1_by_nid(OBJ_cbs2nid(&oid));
if (pqdsa_method != NULL) {
return pqdsa_method;
}
return KEM_find_asn1_by_nid(OBJ_cbs2nid(&oid));
}
EVP_PKEY *EVP_parse_public_key(CBS *cbs) {
// Parse the SubjectPublicKeyInfo.
CBS spki, algorithm, key;
uint8_t padding;
if (!CBS_get_asn1(cbs, &spki, CBS_ASN1_SEQUENCE) ||
!CBS_get_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) ||
!CBS_get_asn1(&spki, &key, CBS_ASN1_BITSTRING) ||
CBS_len(&spki) != 0) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return NULL;
}
CBS oid;
const EVP_PKEY_ASN1_METHOD *method = parse_key_type(&algorithm, &oid);
if (method == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM);
return NULL;
}
if (// Every key type defined encodes the key as a byte string with the same
// conversion to BIT STRING.
!CBS_get_u8(&key, &padding) ||
padding != 0) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return NULL;
}
// Set up an |EVP_PKEY| of the appropriate type.
EVP_PKEY *ret = EVP_PKEY_new();
if (ret == NULL) {
goto err;
}
evp_pkey_set_method(ret, method);
// Call into the type-specific SPKI decoding function.
if (ret->ameth->pub_decode == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM);
goto err;
}
if (!ret->ameth->pub_decode(ret, &oid, &algorithm, &key)) {
goto err;
}
return ret;
err:
EVP_PKEY_free(ret);
return NULL;
}
int EVP_marshal_public_key(CBB *cbb, const EVP_PKEY *key) {
GUARD_PTR(cbb);
GUARD_PTR(key);
if (key->ameth == NULL || key->ameth->pub_encode == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM);
return 0;
}
return key->ameth->pub_encode(cbb, key);
}
static const unsigned kAttributesTag =
CBS_ASN1_CONTEXT_SPECIFIC | 0;
static const unsigned kPublicKeyTag =
CBS_ASN1_CONTEXT_SPECIFIC | 1;
EVP_PKEY *EVP_parse_private_key(CBS *cbs) {
// Parse the PrivateKeyInfo (RFC 5208) or OneAsymmetricKey (RFC 5958).
CBS pkcs8, algorithm, key, public_key;
uint64_t version;
if (!CBS_get_asn1(cbs, &pkcs8, CBS_ASN1_SEQUENCE) ||
!CBS_get_asn1_uint64(&pkcs8, &version) ||
version > PKCS8_VERSION_TWO ||
!CBS_get_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) ||
!CBS_get_asn1(&pkcs8, &key, CBS_ASN1_OCTETSTRING)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return NULL;
}
CBS oid;
const EVP_PKEY_ASN1_METHOD *method = parse_key_type(&algorithm, &oid);
if (method == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM);
return NULL;
}
// A PrivateKeyInfo & OneAsymmetricKey may optionally contain a SET of Attributes which
// we ignore.
if (CBS_peek_asn1_tag(&pkcs8, kAttributesTag)) {
if (!CBS_get_asn1(cbs, NULL, kAttributesTag)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return NULL;
}
}
int has_pub = 0;
// A OneAsymmetricKey may contain an optional PublicKey BIT STRING which is
// implicitly encoded. To support public keys that might not be a size
// divisible by 8 we leave the first octet of the bit string present, which
// specifies the padded bit count between 0 and 7.
if (CBS_peek_asn1_tag(&pkcs8, kPublicKeyTag)) {
if (version != PKCS8_VERSION_TWO || !CBS_get_asn1(&pkcs8, &public_key, kPublicKeyTag)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return NULL;
}
has_pub = 1;
}
// Set up an |EVP_PKEY| of the appropriate type.
EVP_PKEY *ret = EVP_PKEY_new();
if (ret == NULL) {
goto err;
}
evp_pkey_set_method(ret, method);
// Call into the type-specific PrivateKeyInfo decoding function.
if (ret->ameth->priv_decode == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM);
goto err;
}
if (!ret->ameth->priv_decode(ret, &oid, &algorithm, &key,
has_pub ? &public_key : NULL)) {
goto err;
}
return ret;
err:
EVP_PKEY_free(ret);
return NULL;
}
int EVP_marshal_private_key(CBB *cbb, const EVP_PKEY *key) {
if (key->ameth == NULL || key->ameth->priv_encode == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM);
return 0;
}
return key->ameth->priv_encode(cbb, key);
}
int EVP_marshal_private_key_v2(CBB *cbb, const EVP_PKEY *key) {
if (key->ameth == NULL || key->ameth->priv_encode_v2 == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM);
return 0;
}
return key->ameth->priv_encode_v2(cbb, key);
}
static EVP_PKEY *old_priv_decode(CBS *cbs, int type) {
EVP_PKEY *ret = EVP_PKEY_new();
if (ret == NULL) {
return NULL;
}
switch (type) {
case EVP_PKEY_EC: {
EC_KEY *ec_key = EC_KEY_parse_private_key(cbs, NULL);
if (ec_key == NULL || !EVP_PKEY_assign_EC_KEY(ret, ec_key)) {
EC_KEY_free(ec_key);
goto err;
}
return ret;
}
case EVP_PKEY_DSA: {
DSA *dsa = DSA_parse_private_key(cbs);
if (dsa == NULL || !EVP_PKEY_assign_DSA(ret, dsa)) {
DSA_free(dsa);
goto err;
}
return ret;
}
case EVP_PKEY_RSA: {
RSA *rsa = RSA_parse_private_key(cbs);
if (rsa == NULL || !EVP_PKEY_assign_RSA(ret, rsa)) {
RSA_free(rsa);
goto err;
}
return ret;
}
default:
OPENSSL_PUT_ERROR(EVP, EVP_R_UNKNOWN_PUBLIC_KEY_TYPE);
goto err;
}
err:
EVP_PKEY_free(ret);
return NULL;
}
int EVP_PKEY_check(EVP_PKEY_CTX *ctx) {
if (ctx == NULL) {
OPENSSL_PUT_ERROR(EVP, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
EVP_PKEY *pkey = ctx->pkey;
if (pkey == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NO_KEY_SET);
return 0;
}
switch (pkey->type) {
case EVP_PKEY_EC: {
EC_KEY *ec = pkey->pkey.ec;
// For EVP_PKEY_check, ensure the private key exists for EC keys
if (EC_KEY_get0_private_key(ec) == NULL) {
OPENSSL_PUT_ERROR(EVP, EC_R_MISSING_PRIVATE_KEY);
return 0;
}
return EC_KEY_check_key(ec);
}
case EVP_PKEY_RSA:
return RSA_check_key(pkey->pkey.rsa);
default:
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
return 0;
}
}
int EVP_PKEY_public_check(EVP_PKEY_CTX *ctx) {
if (ctx == NULL) {
OPENSSL_PUT_ERROR(EVP, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
EVP_PKEY *pkey = ctx->pkey;
if (pkey == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NO_KEY_SET);
return 0;
}
switch (pkey->type) {
case EVP_PKEY_EC:
return EC_KEY_check_key(pkey->pkey.ec);
case EVP_PKEY_RSA:
return RSA_check_key(pkey->pkey.rsa);
default:
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
return 0;
}
}
int EVP_PKEY_param_check(EVP_PKEY_CTX *ctx) {
if (ctx == NULL) {
OPENSSL_PUT_ERROR(EVP, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
EVP_PKEY *pkey = ctx->pkey;
if (pkey == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NO_KEY_SET);
return 0;
}
int err_flags = 0;
switch (pkey->type) {
case EVP_PKEY_DH:
return DH_check(pkey->pkey.dh, &err_flags) && err_flags == 0;
default:
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
return 0;
}
}
EVP_PKEY *d2i_PrivateKey(int type, EVP_PKEY **out, const uint8_t **inp,
long len) {
if (len < 0) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return NULL;
}
// Parse with the legacy format.
CBS cbs;
CBS_init(&cbs, *inp, (size_t)len);
EVP_PKEY *ret = old_priv_decode(&cbs, type);
if (ret == NULL) {
// Try again with PKCS#8.
ERR_clear_error();
CBS_init(&cbs, *inp, (size_t)len);
ret = EVP_parse_private_key(&cbs);
if (ret == NULL) {
return NULL;
}
if (ret->type != type) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DIFFERENT_KEY_TYPES);
EVP_PKEY_free(ret);
return NULL;
}
}
if (out != NULL) {
EVP_PKEY_free(*out);
*out = ret;
}
*inp = CBS_data(&cbs);
return ret;
}
// num_elements parses one SEQUENCE from |in| and returns the number of elements
// in it. On parse error, it returns zero.
static size_t num_elements(const uint8_t *in, size_t in_len) {
CBS cbs, sequence;
CBS_init(&cbs, in, (size_t)in_len);
if (!CBS_get_asn1(&cbs, &sequence, CBS_ASN1_SEQUENCE)) {
return 0;
}
size_t count = 0;
while (CBS_len(&sequence) > 0) {
if (!CBS_get_any_asn1_element(&sequence, NULL, NULL, NULL)) {
return 0;
}
count++;
}
return count;
}
EVP_PKEY *d2i_AutoPrivateKey(EVP_PKEY **out, const uint8_t **inp, long len) {
if (len < 0) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return NULL;
}
// Parse the input as a PKCS#8 PrivateKeyInfo.
CBS cbs;
CBS_init(&cbs, *inp, (size_t)len);
EVP_PKEY *ret = EVP_parse_private_key(&cbs);
if (ret != NULL) {
if (out != NULL) {
EVP_PKEY_free(*out);
*out = ret;
}
*inp = CBS_data(&cbs);
return ret;
}
ERR_clear_error();
// Count the elements to determine the legacy key format.
switch (num_elements(*inp, (size_t)len)) {
case 4:
return d2i_PrivateKey(EVP_PKEY_EC, out, inp, len);
case 6:
return d2i_PrivateKey(EVP_PKEY_DSA, out, inp, len);
default:
return d2i_PrivateKey(EVP_PKEY_RSA, out, inp, len);
}
}
int i2d_PublicKey(const EVP_PKEY *key, uint8_t **outp) {
switch (key->type) {
case EVP_PKEY_RSA:
return i2d_RSAPublicKey(key->pkey.rsa, outp);
case EVP_PKEY_DSA:
return i2d_DSAPublicKey(key->pkey.dsa, outp);
case EVP_PKEY_EC:
return i2o_ECPublicKey(key->pkey.ec, outp);
default: {
// Fall back to SubjectPublicKeyInfo for key types without legacy
// formats (e.g. Ed25519).
CBB cbb;
if (!CBB_init(&cbb, 128) ||
!EVP_marshal_public_key(&cbb, key)) {
CBB_cleanup(&cbb);
OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE);
return -1;
}
return CBB_finish_i2d(&cbb, outp);
}
}
}
EVP_PKEY *d2i_PublicKey(int type, EVP_PKEY **out, const uint8_t **inp,
long len) {
EVP_PKEY *ret = EVP_PKEY_new();
if (ret == NULL) {
return NULL;
}
CBS cbs;
CBS_init(&cbs, *inp, len < 0 ? 0 : (size_t)len);
switch (type) {
case EVP_PKEY_RSA: {
RSA *rsa = RSA_parse_public_key(&cbs);
if (rsa == NULL || !EVP_PKEY_assign_RSA(ret, rsa)) {
RSA_free(rsa);
goto err;
}
break;
}
// Unlike OpenSSL, we do not support EC keys with this API. The raw EC
// public key serialization requires knowing the group. In OpenSSL, calling
// this function with |EVP_PKEY_EC| and setting |out| to NULL does not work.
// It requires |*out| to include a partially-initialized |EVP_PKEY| to
// extract the group.
default: {
// Fall back to SubjectPublicKeyInfo for key types without legacy
// formats (e.g. Ed25519).
EVP_PKEY_free(ret);
ret = NULL;
ERR_clear_error();
ret = EVP_parse_public_key(&cbs);
if (ret == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE);
goto err;
}
if (ret->type != type) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DIFFERENT_KEY_TYPES);
goto err;
}
break;
}
}
*inp = CBS_data(&cbs);
if (out != NULL) {
EVP_PKEY_free(*out);
*out = ret;
}
return ret;
err:
EVP_PKEY_free(ret);
return NULL;
}
EVP_PKEY *d2i_PUBKEY(EVP_PKEY **out, const uint8_t **inp, long len) {
if (len < 0) {
return NULL;
}
CBS cbs;
CBS_init(&cbs, *inp, (size_t)len);
EVP_PKEY *ret = EVP_parse_public_key(&cbs);
if (ret == NULL) {
return NULL;
}
if (out != NULL) {
EVP_PKEY_free(*out);
*out = ret;
}
*inp = CBS_data(&cbs);
return ret;
}
int i2d_PUBKEY(const EVP_PKEY *pkey, uint8_t **outp) {
if (pkey == NULL) {
return 0;
}
CBB cbb;
if (!CBB_init(&cbb, 128) ||
!EVP_marshal_public_key(&cbb, pkey)) {
CBB_cleanup(&cbb);
return -1;
}
return CBB_finish_i2d(&cbb, outp);
}
RSA *d2i_RSA_PUBKEY(RSA **out, const uint8_t **inp, long len) {
if (len < 0) {
return NULL;
}
CBS cbs;
CBS_init(&cbs, *inp, (size_t)len);
EVP_PKEY *pkey = EVP_parse_public_key(&cbs);
if (pkey == NULL) {
return NULL;
}
RSA *rsa = EVP_PKEY_get1_RSA(pkey);
EVP_PKEY_free(pkey);
if (rsa == NULL) {
return NULL;
}
if (out != NULL) {
RSA_free(*out);
*out = rsa;
}
*inp = CBS_data(&cbs);
return rsa;
}
int i2d_RSA_PUBKEY(const RSA *rsa, uint8_t **outp) {
if (rsa == NULL) {
return 0;
}
int ret = -1;
EVP_PKEY *pkey = EVP_PKEY_new();
if (pkey == NULL ||
!EVP_PKEY_set1_RSA(pkey, (RSA *)rsa)) {
goto err;
}
ret = i2d_PUBKEY(pkey, outp);
err:
EVP_PKEY_free(pkey);
return ret;
}
DSA *d2i_DSA_PUBKEY(DSA **out, const uint8_t **inp, long len) {
if (len < 0) {
return NULL;
}
CBS cbs;
CBS_init(&cbs, *inp, (size_t)len);
EVP_PKEY *pkey = EVP_parse_public_key(&cbs);
if (pkey == NULL) {
return NULL;
}
DSA *dsa = EVP_PKEY_get1_DSA(pkey);
EVP_PKEY_free(pkey);
if (dsa == NULL) {
return NULL;
}
if (out != NULL) {
DSA_free(*out);
*out = dsa;
}
*inp = CBS_data(&cbs);
return dsa;
}
int i2d_DSA_PUBKEY(const DSA *dsa, uint8_t **outp) {
if (dsa == NULL) {
return 0;
}
int ret = -1;
EVP_PKEY *pkey = EVP_PKEY_new();
if (pkey == NULL ||
!EVP_PKEY_set1_DSA(pkey, (DSA *)dsa)) {
goto err;
}
ret = i2d_PUBKEY(pkey, outp);
err:
EVP_PKEY_free(pkey);
return ret;
}
EC_KEY *d2i_EC_PUBKEY(EC_KEY **out, const uint8_t **inp, long len) {
if (len < 0) {
return NULL;
}
CBS cbs;
CBS_init(&cbs, *inp, (size_t)len);
EVP_PKEY *pkey = EVP_parse_public_key(&cbs);
if (pkey == NULL) {
return NULL;
}
EC_KEY *ec_key = EVP_PKEY_get1_EC_KEY(pkey);
EVP_PKEY_free(pkey);
if (ec_key == NULL) {
return NULL;
}
if (out != NULL) {
EC_KEY_free(*out);
*out = ec_key;
}
*inp = CBS_data(&cbs);
return ec_key;
}
int i2d_EC_PUBKEY(const EC_KEY *ec_key, uint8_t **outp) {
if (ec_key == NULL) {
return 0;
}
int ret = -1;
EVP_PKEY *pkey = EVP_PKEY_new();
if (pkey == NULL ||
!EVP_PKEY_set1_EC_KEY(pkey, (EC_KEY *)ec_key)) {
goto err;
}
ret = i2d_PUBKEY(pkey, outp);
err:
EVP_PKEY_free(pkey);
return ret;
}
int EVP_PKEY_asn1_get_count(void) { return asn1_evp_pkey_methods_size; }
const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_get0(int idx) {
if (idx < 0 || idx >= EVP_PKEY_asn1_get_count()) {
return NULL;
}
return asn1_evp_pkey_methods[idx];
}
const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find(ENGINE **_pe, int type) {
for (size_t i = 0; i < (size_t)EVP_PKEY_asn1_get_count(); i++) {
const EVP_PKEY_ASN1_METHOD *ameth = EVP_PKEY_asn1_get0(i);
if (ameth->pkey_id == type) {
return ameth;
}
}
return NULL;
}
const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find_str(ENGINE **_pe,
const char *name, int len) {
if (len < 0) {
return NULL;
}
// OPENSSL_strnlen returns an i, where str[i] == 0
const size_t name_len = OPENSSL_strnlen(name, len);
for (size_t i = 0; i < (size_t)EVP_PKEY_asn1_get_count(); i++) {
const EVP_PKEY_ASN1_METHOD *ameth = EVP_PKEY_asn1_get0(i);
const size_t pem_str_len =
OPENSSL_strnlen(ameth->pem_str, MAX_PEM_STR_LEN);
// OPENSSL_strncasecmp(a, b, n) compares up to index n-1
if (name_len != pem_str_len) {
continue;
}
if (0 == OPENSSL_strncasecmp(ameth->pem_str, name, name_len)) {
return ameth;
}
}
return NULL;
}
int EVP_PKEY_asn1_get0_info(int *ppkey_id, int *pkey_base_id, int *ppkey_flags,
const char **pinfo, const char **ppem_str,
const EVP_PKEY_ASN1_METHOD *ameth) {
if (!ameth) {
return 0;
}
if (ppkey_id) {
*ppkey_id = ameth->pkey_id;
}
if (pkey_base_id) {
*pkey_base_id = ameth->pkey_id;
}
// This value is not supported.
if (ppkey_flags) {
*ppkey_flags = 0;
}
if (pinfo) {
*pinfo = ameth->info;
}
if (ppem_str) {
*ppem_str = ameth->pem_str;
}
return 1;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,56 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR ISC
#ifndef AWS_LC_EVP_EXTRA_INTERNAL_H
#define AWS_LC_EVP_EXTRA_INTERNAL_H
#include <openssl/base.h>
#include "../fipsmodule/evp/internal.h"
#include "../fipsmodule/ml_dsa/ml_dsa.h"
#define PKCS8_VERSION_ONE 0
#define PKCS8_VERSION_TWO 1
#define MAX_PEM_STR_LEN ((size_t)10) // "ED25519ph"
typedef struct {
uint8_t pub[32];
uint8_t priv[32];
char has_private;
} X25519_KEY;
extern const size_t asn1_evp_pkey_methods_size;
extern const EVP_PKEY_ASN1_METHOD *const asn1_evp_pkey_methods[];
extern const EVP_PKEY_ASN1_METHOD dsa_asn1_meth;
extern const EVP_PKEY_ASN1_METHOD ec_asn1_meth;
extern const EVP_PKEY_ASN1_METHOD rsa_asn1_meth;
extern const EVP_PKEY_ASN1_METHOD rsa_pss_asn1_meth;
extern const EVP_PKEY_ASN1_METHOD ed25519_asn1_meth;
extern const EVP_PKEY_ASN1_METHOD x25519_asn1_meth;
extern const EVP_PKEY_ASN1_METHOD pqdsa_asn1_meth;
extern const EVP_PKEY_ASN1_METHOD kem_asn1_meth;
extern const EVP_PKEY_ASN1_METHOD hmac_asn1_meth;
extern const EVP_PKEY_ASN1_METHOD dh_asn1_meth;
extern const EVP_PKEY_ASN1_METHOD ed25519ph_asn1_meth;
extern const EVP_PKEY_METHOD x25519_pkey_meth;
extern const EVP_PKEY_METHOD hkdf_pkey_meth;
extern const EVP_PKEY_METHOD hmac_pkey_meth;
extern const EVP_PKEY_METHOD dh_pkey_meth;
extern const EVP_PKEY_METHOD dsa_pkey_meth;
extern const EVP_PKEY_METHOD pqdsa_pkey_meth;
// evp_pkey_set_method behaves like |EVP_PKEY_set_type|, but takes a pointer to
// a method table. This avoids depending on every |EVP_PKEY_ASN1_METHOD|.
void evp_pkey_set_method(EVP_PKEY *pkey, const EVP_PKEY_ASN1_METHOD *method);
// Returns a reference to the list |non_fips_pkey_evp_methods|. The list has
// size |NON_FIPS_EVP_PKEY_METHODS|.
const EVP_PKEY_METHOD *const *AWSLC_non_fips_pkey_evp_methods(void);
// Returns a reference to the list |asn1_evp_pkey_methods|. The list has
// size |ASN1_EVP_PKEY_METHODS|.
const EVP_PKEY_ASN1_METHOD *const *AWSLC_non_fips_pkey_evp_asn1_methods(void);
#endif

View File

@@ -0,0 +1,57 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR ISC
#include <gtest/gtest.h>
#include <openssl/evp.h>
#include <openssl/obj.h>
#include "../test/file_test.h"
// ML-DSA parameter sets
struct MLDSAParamSet {
const char name[20];
const int nid;
};
static const struct MLDSAParamSet kMLDSAs[] = {{"MLDSA44", NID_MLDSA44},
{"MLDSA65", NID_MLDSA65},
{"MLDSA87", NID_MLDSA87}};
class MLDSATest : public testing::TestWithParam<MLDSAParamSet> {};
INSTANTIATE_TEST_SUITE_P(All, MLDSATest, testing::ValuesIn(kMLDSAs),
[](const testing::TestParamInfo<MLDSAParamSet> &params)
-> std::string { return params.param.name; });
TEST_P(MLDSATest, ExpandedKeyValidation) {
const MLDSAParamSet ps = GetParam();
// This test verifies that we reject invalid extended keys, because they can
// cause undefined behavior including producing unverifiable signatures.
//
// Test vectors are generated by make_corrupted_key_tests.cc which uses
// internal ML-DSA functions to corrupt keys in specific ways.
FileTestGTest("crypto/evp_extra/mldsa_corrupted_key_tests.txt",
[&](FileTest *t) {
std::string param_set;
ASSERT_TRUE(t->GetInstruction(&param_set, "ParamSet"));
// Skip test vectors for other parameter sets
if (param_set != ps.name) {
t->SkipCurrent();
return;
}
std::vector<uint8_t> corrupted_key;
ASSERT_TRUE(t->GetBytes(&corrupted_key, "CorruptedKey"));
// Try to import the corrupted key - it should fail
bssl::UniquePtr<EVP_PKEY> corrupted_pkey(
EVP_PKEY_pqdsa_new_raw_private_key(
ps.nid, corrupted_key.data(), corrupted_key.size()));
EXPECT_FALSE(corrupted_pkey.get())
<< "Imported corrupted " << ps.name << " key";
});
}

View File

@@ -0,0 +1,234 @@
// Copyright 2006-2019 The OpenSSL Project Authors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
#include <string.h>
#include <openssl/evp.h>
#include <assert.h>
#include <openssl/dh.h>
#include <openssl/err.h>
#include <openssl/mem.h>
#include "internal.h"
typedef struct dh_pkey_ctx_st {
int pad;
/* Parameter gen parameters */
int prime_len;
int generator;
} DH_PKEY_CTX;
static int pkey_dh_init(EVP_PKEY_CTX *ctx) {
DH_PKEY_CTX *dctx = OPENSSL_zalloc(sizeof(DH_PKEY_CTX));
if (dctx == NULL) {
return 0;
}
// Default parameters
dctx->prime_len = 2048;
dctx->generator = DH_GENERATOR_2;
ctx->data = dctx;
return 1;
}
static int pkey_dh_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) {
if (!pkey_dh_init(dst)) {
return 0;
}
const DH_PKEY_CTX *sctx = src->data;
DH_PKEY_CTX *dctx = dst->data;
dctx->pad = sctx->pad;
return 1;
}
static void pkey_dh_cleanup(EVP_PKEY_CTX *ctx) {
OPENSSL_free(ctx->data);
ctx->data = NULL;
}
static int pkey_dh_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) {
DH *dh = DH_new();
if (dh == NULL || !EVP_PKEY_assign_DH(pkey, dh)) {
DH_free(dh);
return 0;
}
if (ctx->pkey != NULL && !EVP_PKEY_copy_parameters(pkey, ctx->pkey)) {
return 0;
}
return DH_generate_key(dh);
}
static int pkey_dh_derive(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *out_len) {
DH_PKEY_CTX *dctx = ctx->data;
if (ctx->pkey == NULL || ctx->peerkey == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_KEYS_NOT_SET);
return 0;
}
DH *our_key = ctx->pkey->pkey.dh;
DH *peer_key = ctx->peerkey->pkey.dh;
if (our_key == NULL || peer_key == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_KEYS_NOT_SET);
return 0;
}
const BIGNUM *pub_key = DH_get0_pub_key(peer_key);
if (pub_key == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_KEYS_NOT_SET);
return 0;
}
if (out == NULL) {
*out_len = DH_size(our_key);
return 1;
}
if (*out_len < (size_t)DH_size(our_key)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
return 0;
}
int ret = dctx->pad ? DH_compute_key_padded(out, pub_key, our_key)
: DH_compute_key(out, pub_key, our_key);
if (ret < 0) {
return 0;
}
assert(ret <= DH_size(our_key));
*out_len = (size_t)ret;
return 1;
}
static int pkey_dh_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *_p2) {
DH_PKEY_CTX *dctx = ctx->data;
switch (type) {
case EVP_PKEY_CTRL_PEER_KEY:
// |EVP_PKEY_derive_set_peer| requires the key implement this command,
// even if it is a no-op.
return 1;
case EVP_PKEY_CTRL_DH_PAD:
dctx->pad = p1;
return 1;
case EVP_PKEY_CTRL_DH_PARAMGEN_PRIME_LEN:
if(p1 < 256) {
return -2;
}
dctx->prime_len = p1;
return 1;
case EVP_PKEY_CTRL_DH_PARAMGEN_GENERATOR:
if(p1 < 2) {
return -2;
}
dctx->generator = p1;
return 1;
default:
OPENSSL_PUT_ERROR(EVP, EVP_R_COMMAND_NOT_SUPPORTED);
return 0;
}
}
static int pkey_dh_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) {
int ret = 0;
DH_PKEY_CTX *dctx = ctx->data;
DH *dh = DH_new();
if (dh == NULL) {
return 0;
}
BN_GENCB *pkey_ctx_cb = NULL;
if (ctx->pkey_gencb) {
pkey_ctx_cb = BN_GENCB_new();
if (pkey_ctx_cb == NULL) {
goto end;
}
evp_pkey_set_cb_translate(pkey_ctx_cb, ctx);
}
ret = DH_generate_parameters_ex(dh, dctx->prime_len, dctx->generator, pkey_ctx_cb);
end:
if (ret == 1) {
EVP_PKEY_assign_DH(pkey, dh);
} else {
ret = 0;
DH_free(dh);
}
BN_GENCB_free(pkey_ctx_cb);
return ret;
}
static int pkey_dh_ctrl_str(EVP_PKEY_CTX *ctx, const char *type,
const char *value) {
// We don't support:
// * dh_rfc5114
// * dh_param
// * dh_paramgen_subprime_len
// * dh_paramgen_type
if (strcmp(type, "dh_paramgen_prime_len") == 0) {
char* str_end = NULL;
long prime_len = strtol(value, &str_end, 10);
if(str_end == value || prime_len < 0 || prime_len > INT_MAX) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_OPERATION);
return 0;
}
return EVP_PKEY_CTX_set_dh_paramgen_prime_len(ctx, (int)prime_len);
}
if (strcmp(type, "dh_paramgen_generator") == 0) {
char* str_end = NULL;
long generator = strtol(value, &str_end, 10);
if(str_end == value || generator < 0 || generator > INT_MAX) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_OPERATION);
return 0;
}
return EVP_PKEY_CTX_set_dh_paramgen_generator(ctx, (int)generator);
}
if (strcmp(type, "dh_pad") == 0) {
char* str_end = NULL;
long pad = strtol(value, &str_end, 10);
if(str_end == value || pad < 0 || pad > INT_MAX) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_OPERATION);
return 0;
}
return EVP_PKEY_CTX_set_dh_pad(ctx, (int)pad);
}
return -2;
}
const EVP_PKEY_METHOD dh_pkey_meth = {
.pkey_id = EVP_PKEY_DH,
.init = pkey_dh_init,
.copy = pkey_dh_copy,
.cleanup = pkey_dh_cleanup,
.keygen = pkey_dh_keygen,
.derive = pkey_dh_derive,
.paramgen = pkey_dh_paramgen,
.ctrl = pkey_dh_ctrl,
.ctrl_str = pkey_dh_ctrl_str
};
int EVP_PKEY_CTX_set_dh_pad(EVP_PKEY_CTX *ctx, int pad) {
return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DH, EVP_PKEY_OP_DERIVE,
EVP_PKEY_CTRL_DH_PAD, pad, NULL);
}
int EVP_PKEY_CTX_set_dh_paramgen_prime_len(EVP_PKEY_CTX *ctx, int pbits) {
return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DH, EVP_PKEY_OP_PARAMGEN,
EVP_PKEY_CTRL_DH_PARAMGEN_PRIME_LEN, pbits, NULL);
}
int EVP_PKEY_CTX_set_dh_paramgen_generator(EVP_PKEY_CTX *ctx, int gen) {
return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DH, EVP_PKEY_OP_PARAMGEN,
EVP_PKEY_CTRL_DH_PARAMGEN_GENERATOR, gen, NULL);
}

View File

@@ -0,0 +1,204 @@
// Copyright 2006-2021 The OpenSSL Project Authors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
#include <openssl/evp.h>
#include <openssl/bn.h>
#include <openssl/dh.h>
#include <openssl/err.h>
#include <openssl/x509.h>
#include "../fipsmodule/cpucap/internal.h"
#include "../fipsmodule/dh/internal.h"
#include "../internal.h"
#include "internal.h"
static int dh_pub_encode(CBB *out, const EVP_PKEY *key) {
const DH *dh = key->pkey.dh;
if (dh == NULL || dh->pub_key == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
return 0;
}
CBB spki, algorithm, oid, key_bitstring;
if (!CBB_add_asn1(out, &spki, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) ||
!CBB_add_bytes(&oid, dh_asn1_meth.oid, dh_asn1_meth.oid_len) ||
!DH_marshal_parameters(&algorithm, key->pkey.dh) ||
!CBB_add_asn1(&spki, &key_bitstring, CBS_ASN1_BITSTRING) ||
!CBB_add_u8(&key_bitstring, 0 /* padding */) ||
!BN_marshal_asn1(&key_bitstring, key->pkey.dh->pub_key) ||
!CBB_flush(out)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
return 0;
}
return 1;
}
static int dh_pub_decode(EVP_PKEY *out, CBS *oid, CBS *params, CBS *key) {
// RFC 2786
BIGNUM *pubkey = NULL;
DH *dh = NULL;
if (out == NULL || params == NULL || CBS_len(params) == 0 || key == NULL ||
CBS_len(key) == 0) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
goto err;
}
dh = DH_parse_parameters(params);
if (dh == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
goto err;
}
pubkey = BN_new();
if (pubkey == NULL || !BN_parse_asn1_unsigned(key, pubkey) || CBS_len(key) != 0) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
goto err;
}
int out_flags = 0;
if (!DH_check_pub_key(dh, pubkey, &out_flags) || out_flags != 0) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
goto err;
}
dh->pub_key = pubkey;
pubkey = NULL;
if (!EVP_PKEY_assign_DH(out, dh)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
goto err;
}
return 1;
err:
DH_free(dh);
BN_free(pubkey);
return 0;
}
static void dh_free(EVP_PKEY *pkey) {
DH_free(pkey->pkey.dh);
pkey->pkey.dh = NULL;
}
static int dh_size(const EVP_PKEY *pkey) { return DH_size(pkey->pkey.dh); }
static int dh_bits(const EVP_PKEY *pkey) { return DH_bits(pkey->pkey.dh); }
static int dh_param_missing(const EVP_PKEY *pkey) {
const DH *dh = pkey->pkey.dh;
return dh == NULL || DH_get0_p(dh) == NULL || DH_get0_g(dh) == NULL;
}
static int dh_param_copy(EVP_PKEY *to, const EVP_PKEY *from) {
if (dh_param_missing(from)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_MISSING_PARAMETERS);
return 0;
}
// Ensure the target has an allocated DH structure.
if (to->pkey.dh == NULL) {
to->pkey.dh = DH_new();
if (to->pkey.dh == NULL) {
return 0;
}
}
const DH *dh = from->pkey.dh;
const BIGNUM *q_old = DH_get0_q(dh);
BIGNUM *p = BN_dup(DH_get0_p(dh));
BIGNUM *q = q_old == NULL ? NULL : BN_dup(q_old);
BIGNUM *g = BN_dup(DH_get0_g(dh));
if (p == NULL || (q_old != NULL && q == NULL) || g == NULL ||
!DH_set0_pqg(to->pkey.dh, p, q, g)) {
BN_free(p);
BN_free(q);
BN_free(g);
return 0;
}
// |DH_set0_pqg| took ownership of |p|, |q|, and |g|.
return 1;
}
static int dh_param_cmp(const EVP_PKEY *a, const EVP_PKEY *b) {
if (dh_param_missing(a) || dh_param_missing(b)) {
return -2;
}
// Matching OpenSSL, only compare p and g for PKCS#3-style Diffie-Hellman.
// OpenSSL only checks q in X9.42-style Diffie-Hellman ("DHX").
const DH *a_dh = a->pkey.dh;
const DH *b_dh = b->pkey.dh;
return BN_cmp(DH_get0_p(a_dh), DH_get0_p(b_dh)) == 0 &&
BN_cmp(DH_get0_g(a_dh), DH_get0_g(b_dh)) == 0;
}
static int dh_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) {
if (dh_param_cmp(a, b) <= 0) {
return 0;
}
const DH *a_dh = a->pkey.dh;
const DH *b_dh = b->pkey.dh;
return BN_cmp(DH_get0_pub_key(a_dh), DH_get0_pub_key(b_dh)) == 0;
}
const EVP_PKEY_ASN1_METHOD dh_asn1_meth = {
.pkey_id = EVP_PKEY_DH,
// 1.2.840.113549.1.3.1
// ((1)*40 + (2)) = 42 = 0x2a
// 840 = 0b_0000110_1001000 => 0b_1000_0110_0100_1000 = 0x86 0x48
// 113549 = 0b_0000110_1110111_0001101 => 0b_1000_0110_1111_0111_0000_1101 = 0x86 0xF7 0x0D
.oid = {0x2a, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x03, 0x01},
.oid_len = 9,
.pem_str = "DH",
.info = "OpenSSL PKCS#3 DH method",
.pub_cmp = dh_pub_cmp,
.pkey_size = dh_size,
.pkey_bits = dh_bits,
.param_missing = dh_param_missing,
.param_copy = dh_param_copy,
.param_cmp = dh_param_cmp,
.pkey_free = dh_free,
.pub_encode = dh_pub_encode,
.pub_decode = dh_pub_decode,
};
int EVP_PKEY_set1_DH(EVP_PKEY *pkey, DH *key) {
SET_DIT_AUTO_RESET
if (EVP_PKEY_assign_DH(pkey, key)) {
DH_up_ref(key);
return 1;
}
return 0;
}
int EVP_PKEY_assign_DH(EVP_PKEY *pkey, DH *key) {
SET_DIT_AUTO_RESET
evp_pkey_set_method(pkey, &dh_asn1_meth);
pkey->pkey.dh = key;
return key != NULL;
}
DH *EVP_PKEY_get0_DH(const EVP_PKEY *pkey) {
SET_DIT_AUTO_RESET
if (pkey->type != EVP_PKEY_DH) {
OPENSSL_PUT_ERROR(EVP, EVP_R_EXPECTING_A_DH_KEY);
return NULL;
}
return pkey->pkey.dh;
}
DH *EVP_PKEY_get1_DH(const EVP_PKEY *pkey) {
SET_DIT_AUTO_RESET
DH *dh = EVP_PKEY_get0_DH(pkey);
if (dh != NULL) {
DH_up_ref(dh);
}
return dh;
}

View File

@@ -0,0 +1,360 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR ISC
#include <openssl/dsa.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include "../dsa/internal.h"
#include "../internal.h"
#include "./internal.h"
typedef struct {
int nbits; // defaults to 2048
int qbits;
const EVP_MD *pmd; // MD for paramgen
const EVP_MD *md; // MD for signing
} DSA_PKEY_CTX;
static int pkey_dsa_init(EVP_PKEY_CTX *ctx) {
DSA_PKEY_CTX *dctx = NULL;
if (!(dctx = (DSA_PKEY_CTX *)OPENSSL_zalloc(sizeof(DSA_PKEY_CTX)))) {
return 0;
}
dctx->nbits = 2048;
dctx->qbits = 256;
dctx->pmd = NULL;
dctx->md = NULL;
ctx->data = dctx;
return 1;
}
static int pkey_dsa_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) {
DSA_PKEY_CTX *dctx = NULL;
DSA_PKEY_CTX *sctx = NULL;
if (!pkey_dsa_init(dst)) {
return 0;
}
sctx = (DSA_PKEY_CTX *)src->data;
dctx = (DSA_PKEY_CTX *)dst->data;
if (sctx == NULL || dctx == NULL) {
return 0;
}
dctx->nbits = sctx->nbits;
dctx->qbits = sctx->qbits;
dctx->pmd = sctx->pmd;
dctx->md = sctx->md;
return 1;
}
static void pkey_dsa_cleanup(EVP_PKEY_CTX *ctx) {
OPENSSL_free(ctx->data);
ctx->data = NULL;
}
static int pkey_dsa_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) {
GUARD_PTR(ctx->pkey);
DSA *dsa = DSA_new();
if (dsa == NULL || !EVP_PKEY_assign_DSA(pkey, dsa)) {
DSA_free(dsa);
return 0;
}
// |pkey| now has ownership of DSA, and EVP_PKEY_free will handle from this
// point on.
if (!EVP_PKEY_copy_parameters(pkey, ctx->pkey)) {
return 0;
}
return DSA_generate_key(pkey->pkey.dsa);
}
static int pkey_dsa_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) {
BN_GENCB *pkey_ctx_cb = NULL;
DSA *dsa = NULL;
DSA_PKEY_CTX *dctx = (DSA_PKEY_CTX *)ctx->data;
GUARD_PTR(dctx);
int ret = 0;
if (ctx->pkey_gencb) {
pkey_ctx_cb = BN_GENCB_new();
if (pkey_ctx_cb == NULL) {
goto end;
}
evp_pkey_set_cb_translate(pkey_ctx_cb, ctx);
}
const EVP_MD *pmd = dctx->pmd;
if (pmd == NULL) {
switch (dctx->qbits) {
case 160:
pmd = EVP_sha1();
break;
case 224:
pmd = EVP_sha224();
break;
case 256:
pmd = EVP_sha256();
break;
default:
// This should not be possible.
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_OPERATION);
goto end;
}
}
if (!((dsa = DSA_new()))) {
goto end;
}
if (!dsa_internal_paramgen(dsa, dctx->nbits, pmd, NULL, 0, NULL, NULL,
pkey_ctx_cb)) {
goto end;
}
ret = EVP_PKEY_assign_DSA(pkey, dsa);
end:
BN_GENCB_free(pkey_ctx_cb);
if (ret != 1) {
OPENSSL_free(dsa);
}
return ret;
}
static int pkey_dsa_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
const unsigned char *tbs, size_t tbslen) {
GUARD_PTR(ctx->pkey);
GUARD_PTR(ctx->pkey->pkey.ptr);
GUARD_PTR(ctx->data);
GUARD_PTR(siglen);
DSA_PKEY_CTX *dctx = ctx->data;
DSA *dsa = ctx->pkey->pkey.dsa;
if (sig == NULL) {
// Passing NULL for sig indicates a query for the size of the signature
*siglen = DSA_size(dsa);
return 1;
}
DSA_SIG *result = NULL;
uint8_t *sig_buffer = NULL;
int retval = 0;
if (dctx->md != NULL && tbslen != EVP_MD_size(dctx->md)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PARAMETERS);
goto end;
}
result = DSA_do_sign(tbs, tbslen, dsa);
if (result == NULL) {
goto end;
}
CBB sig_bytes;
if (1 != CBB_init(&sig_bytes, tbslen)) {
goto end;
}
DSA_SIG_marshal(&sig_bytes, result);
if (1 != CBB_finish(&sig_bytes, &sig_buffer, siglen)) {
goto end;
}
OPENSSL_memcpy(sig, sig_buffer, *siglen);
retval = 1;
end:
OPENSSL_free(sig_buffer);
DSA_SIG_free(result);
return retval;
}
static int pkey_dsa_verify(EVP_PKEY_CTX *ctx, const unsigned char *sig,
size_t siglen, const unsigned char *tbs,
size_t tbslen) {
GUARD_PTR(ctx->pkey);
GUARD_PTR(ctx->pkey->pkey.ptr);
GUARD_PTR(ctx->data);
GUARD_PTR(tbs);
DSA_PKEY_CTX *dctx = ctx->data;
const DSA *dsa = ctx->pkey->pkey.dsa;
if (dctx->md != NULL && tbslen != EVP_MD_size(dctx->md)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PARAMETERS);
return 0;
}
DSA_SIG *dsa_sig = NULL;
int retval = 0;
CBS sig_cbs;
CBS_init(&sig_cbs, sig, siglen);
dsa_sig = DSA_SIG_parse(&sig_cbs);
// Allocation failure, invalid asn1 encoding, or trailing garbage
if (dsa_sig == NULL || CBS_len(&sig_cbs) != 0) {
goto end;
}
if (1 != DSA_do_verify(tbs, tbslen, dsa_sig, dsa)) {
goto end;
}
retval = 1;
end:
DSA_SIG_free(dsa_sig);
return retval;
}
static int pkey_dsa_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) {
DSA_PKEY_CTX *dctx = ctx->data;
switch (type) {
case EVP_PKEY_CTRL_DSA_PARAMGEN_BITS:
if (p1 < 512) {
return -2;
}
dctx->nbits = p1;
return 1;
case EVP_PKEY_CTRL_DSA_PARAMGEN_Q_BITS: {
switch (p1) {
case 160:
case 224:
case 256:
dctx->qbits = p1;
return 1;
default:
return -2;
}
}
case EVP_PKEY_CTRL_DSA_PARAMGEN_MD: {
const EVP_MD *pmd = (const EVP_MD *)p2;
if (pmd == NULL) {
return 0;
}
switch (EVP_MD_type(pmd)) {
case NID_sha1:
case NID_sha224:
case NID_sha256:
dctx->pmd = pmd;
return 1;
default:
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_DIGEST_TYPE);
return 0;
}
}
case EVP_PKEY_CTRL_MD: {
const EVP_MD *md = (const EVP_MD *)p2;
if (md == NULL) {
return 0;
}
switch (EVP_MD_type(md)) {
case NID_sha1:
case NID_sha224:
case NID_sha256:
case NID_sha384:
case NID_sha512:
case NID_sha3_224:
case NID_sha3_256:
case NID_sha3_384:
case NID_sha3_512:
dctx->md = md;
return 1;
default:
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_DIGEST_TYPE);
return 0;
}
}
case EVP_PKEY_CTRL_GET_MD:
if (p2 == NULL) {
return 0;
}
*(const EVP_MD **)p2 = dctx->md;
return 1;
case EVP_PKEY_CTRL_PEER_KEY:
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
return -2;
default:
OPENSSL_PUT_ERROR(EVP, EVP_R_COMMAND_NOT_SUPPORTED);
return 0;
}
}
static int pkey_dsa_ctrl_str(EVP_PKEY_CTX *ctx, const char *type,
const char *value) {
if (strcmp(type, "dsa_paramgen_bits") == 0) {
char *str_end = NULL;
long nbits = strtol(value, &str_end, 10);
if (str_end == value || nbits < 0 || nbits > INT_MAX) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_OPERATION);
return 0;
}
OPENSSL_BEGIN_ALLOW_DEPRECATED
return EVP_PKEY_CTX_set_dsa_paramgen_bits(ctx, (int)nbits);
OPENSSL_END_ALLOW_DEPRECATED
}
if (strcmp(type, "dsa_paramgen_q_bits") == 0) {
char *str_end = NULL;
long qbits = strtol(value, &str_end, 10);
if (str_end == value || qbits < 0 || qbits > INT_MAX) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_OPERATION);
return 0;
}
OPENSSL_BEGIN_ALLOW_DEPRECATED
return EVP_PKEY_CTX_set_dsa_paramgen_q_bits(ctx, (int)qbits);
OPENSSL_END_ALLOW_DEPRECATED
}
if (strcmp(type, "dsa_paramgen_md") == 0) {
const EVP_MD *md = EVP_get_digestbyname(value);
if (md == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_DIGEST_TYPE);
return 0;
}
OPENSSL_BEGIN_ALLOW_DEPRECATED
return EVP_PKEY_CTX_set_dsa_paramgen_md(ctx, md);
OPENSSL_END_ALLOW_DEPRECATED
}
return -2;
}
const EVP_PKEY_METHOD dsa_pkey_meth = {.pkey_id = EVP_PKEY_DSA,
.init = pkey_dsa_init,
.copy = pkey_dsa_copy,
.cleanup = pkey_dsa_cleanup,
.keygen = pkey_dsa_keygen,
.paramgen = pkey_dsa_paramgen,
.sign = pkey_dsa_sign,
.verify = pkey_dsa_verify,
.ctrl = pkey_dsa_ctrl,
.ctrl_str = pkey_dsa_ctrl_str};
int EVP_PKEY_CTX_set_dsa_paramgen_bits(EVP_PKEY_CTX *ctx, int nbits) {
if (1 == EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DSA, EVP_PKEY_OP_PARAMGEN,
EVP_PKEY_CTRL_DSA_PARAMGEN_BITS, nbits, NULL)) {
return 1;
}
return 0;
}
int EVP_PKEY_CTX_set_dsa_paramgen_q_bits(EVP_PKEY_CTX *ctx, int qbits) {
if (1 == EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DSA, EVP_PKEY_OP_PARAMGEN,
EVP_PKEY_CTRL_DSA_PARAMGEN_Q_BITS, qbits, NULL)) {
return 1;
}
return 0;
}
int EVP_PKEY_CTX_set_dsa_paramgen_md(EVP_PKEY_CTX *ctx, const EVP_MD *md) {
if (1 == EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DSA, EVP_PKEY_OP_PARAMGEN,
EVP_PKEY_CTRL_DSA_PARAMGEN_MD, 0, (void *)md)) {
return 1;
}
return 0;
}

View File

@@ -0,0 +1,240 @@
// Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project 2006.
// Copyright (c) 2006 The OpenSSL Project. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
#include <openssl/evp.h>
#include <openssl/digest.h>
#include <openssl/bn.h>
#include <openssl/bytestring.h>
#include <openssl/dsa.h>
#include <openssl/err.h>
#include "../fipsmodule/evp/internal.h"
#include "../dsa/internal.h"
#include "internal.h"
static int dsa_pub_decode(EVP_PKEY *out, CBS *oid, CBS *params, CBS *key) {
// See RFC 3279, section 2.3.2.
// Parameters may or may not be present.
DSA *dsa;
if (CBS_len(params) == 0) {
dsa = DSA_new();
if (dsa == NULL) {
return 0;
}
} else {
dsa = DSA_parse_parameters(params);
if (dsa == NULL || CBS_len(params) != 0) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
goto err;
}
}
dsa->pub_key = BN_new();
if (dsa->pub_key == NULL) {
goto err;
}
if (!BN_parse_asn1_unsigned(key, dsa->pub_key) ||
CBS_len(key) != 0) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
goto err;
}
if(1 == EVP_PKEY_assign_DSA(out, dsa)) {
return 1;
}
err:
DSA_free(dsa);
return 0;
}
static int dsa_pub_encode(CBB *out, const EVP_PKEY *key) {
const DSA *dsa = key->pkey.dsa;
const int has_params = dsa->p != NULL && dsa->q != NULL && dsa->g != NULL;
// See RFC 5480, section 2.
CBB spki, algorithm, oid, key_bitstring;
if (!CBB_add_asn1(out, &spki, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) ||
!CBB_add_bytes(&oid, dsa_asn1_meth.oid, dsa_asn1_meth.oid_len) ||
(has_params &&
!DSA_marshal_parameters(&algorithm, dsa)) ||
!CBB_add_asn1(&spki, &key_bitstring, CBS_ASN1_BITSTRING) ||
!CBB_add_u8(&key_bitstring, 0 /* padding */) ||
!BN_marshal_asn1(&key_bitstring, dsa->pub_key) ||
!CBB_flush(out)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
return 0;
}
return 1;
}
static int dsa_priv_decode(EVP_PKEY *out, CBS *oid, CBS *params, CBS *key, CBS *pubkey) {
// See PKCS#11, v2.40, section 2.5.
if(pubkey) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return 0;
}
// Decode parameters.
BN_CTX *ctx = NULL;
DSA *dsa = DSA_parse_parameters(params);
if (dsa == NULL || CBS_len(params) != 0) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
goto err;
}
dsa->priv_key = BN_new();
if (dsa->priv_key == NULL) {
goto err;
}
if (!BN_parse_asn1_unsigned(key, dsa->priv_key) ||
CBS_len(key) != 0) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
goto err;
}
// To avoid DoS attacks when importing private keys, check bounds on |dsa|.
// This bounds |dsa->priv_key| against |dsa->q| and bounds |dsa->q|'s bit
// width.
if (!dsa_check_key(dsa)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
goto err;
}
// Calculate the public key.
ctx = BN_CTX_new();
dsa->pub_key = BN_new();
if (ctx == NULL || dsa->pub_key == NULL ||
!BN_mod_exp_mont_consttime(dsa->pub_key, dsa->g, dsa->priv_key, dsa->p,
ctx, NULL)) {
goto err;
}
if(1 == EVP_PKEY_assign_DSA(out, dsa)) {
BN_CTX_free(ctx);
return 1;
}
err:
BN_CTX_free(ctx);
DSA_free(dsa);
return 0;
}
static int dsa_priv_encode(CBB *out, const EVP_PKEY *key) {
const DSA *dsa = key->pkey.dsa;
if (dsa == NULL || dsa->priv_key == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_MISSING_PARAMETERS);
return 0;
}
// See PKCS#11, v2.40, section 2.5.
CBB pkcs8, algorithm, oid, private_key;
if (!CBB_add_asn1(out, &pkcs8, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1_uint64(&pkcs8, PKCS8_VERSION_ONE /* version */) ||
!CBB_add_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) ||
!CBB_add_bytes(&oid, dsa_asn1_meth.oid, dsa_asn1_meth.oid_len) ||
!DSA_marshal_parameters(&algorithm, dsa) ||
!CBB_add_asn1(&pkcs8, &private_key, CBS_ASN1_OCTETSTRING) ||
!BN_marshal_asn1(&private_key, dsa->priv_key) ||
!CBB_flush(out)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
return 0;
}
return 1;
}
static int int_dsa_size(const EVP_PKEY *pkey) {
return DSA_size(pkey->pkey.dsa);
}
static int dsa_bits(const EVP_PKEY *pkey) {
return BN_num_bits(pkey->pkey.dsa->p);
}
static int dsa_missing_parameters(const EVP_PKEY *pkey) {
DSA *dsa;
dsa = pkey->pkey.dsa;
if (dsa->p == NULL || dsa->q == NULL || dsa->g == NULL) {
return 1;
}
return 0;
}
static int dup_bn_into(BIGNUM **out, BIGNUM *src) {
BIGNUM *a;
a = BN_dup(src);
if (a == NULL) {
return 0;
}
BN_free(*out);
*out = a;
return 1;
}
static int dsa_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from) {
if (!dup_bn_into(&to->pkey.dsa->p, from->pkey.dsa->p) ||
!dup_bn_into(&to->pkey.dsa->q, from->pkey.dsa->q) ||
!dup_bn_into(&to->pkey.dsa->g, from->pkey.dsa->g)) {
return 0;
}
return 1;
}
static int dsa_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b) {
return BN_cmp(a->pkey.dsa->p, b->pkey.dsa->p) == 0 &&
BN_cmp(a->pkey.dsa->q, b->pkey.dsa->q) == 0 &&
BN_cmp(a->pkey.dsa->g, b->pkey.dsa->g) == 0;
}
static int dsa_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) {
return BN_cmp(b->pkey.dsa->pub_key, a->pkey.dsa->pub_key) == 0;
}
static void int_dsa_free(EVP_PKEY *pkey) { DSA_free(pkey->pkey.dsa); }
const EVP_PKEY_ASN1_METHOD dsa_asn1_meth = {
EVP_PKEY_DSA,
// 1.2.840.10040.4.1
{0x2a, 0x86, 0x48, 0xce, 0x38, 0x04, 0x01}, 7,
"DSA",
"OpenSSL DSA method",
dsa_pub_decode,
dsa_pub_encode,
dsa_pub_cmp,
dsa_priv_decode,
dsa_priv_encode,
NULL /* priv_encode_v2 */,
NULL /* set_priv_raw */,
NULL /* set_pub_raw */,
NULL /* get_priv_raw */,
NULL /* get_pub_raw */,
NULL /* pkey_opaque */,
int_dsa_size,
dsa_bits,
dsa_missing_parameters,
dsa_copy_parameters,
dsa_cmp_parameters,
int_dsa_free,
};

View File

@@ -0,0 +1,250 @@
// Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project 2006.
// Copyright (c) 2006 The OpenSSL Project. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
#include <openssl/evp.h>
#include <openssl/bn.h>
#include <openssl/bytestring.h>
#include <openssl/ec.h>
#include <openssl/ec_key.h>
#include <openssl/ecdsa.h>
#include <openssl/err.h>
#include "../fipsmodule/evp/internal.h"
#include "../ec_extra/internal.h"
#include "internal.h"
static int eckey_pub_encode(CBB *out, const EVP_PKEY *key) {
const EC_KEY *ec_key = key->pkey.ec;
const EC_GROUP *group = EC_KEY_get0_group(ec_key);
const EC_POINT *public_key = EC_KEY_get0_public_key(ec_key);
// See RFC 5480, section 2.
CBB spki, algorithm, oid, key_bitstring;
if (!CBB_add_asn1(out, &spki, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) ||
!CBB_add_bytes(&oid, ec_asn1_meth.oid, ec_asn1_meth.oid_len) ||
!EC_KEY_marshal_curve_name(&algorithm, group) ||
!CBB_add_asn1(&spki, &key_bitstring, CBS_ASN1_BITSTRING) ||
!CBB_add_u8(&key_bitstring, 0 /* padding */) ||
!EC_POINT_point2cbb(&key_bitstring, group, public_key,
POINT_CONVERSION_UNCOMPRESSED, NULL) ||
!CBB_flush(out)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
return 0;
}
return 1;
}
static int eckey_pub_decode(EVP_PKEY *out, CBS *oid, CBS *params, CBS *key) {
// See RFC 5480, section 2.
// The parameters are a named curve.
EC_POINT *point = NULL;
EC_KEY *eckey = NULL;
enum ECParametersType paramType = UNKNOWN_EC_PARAMETERS;
const EC_GROUP *group = EC_KEY_parse_parameters_and_type(params, &paramType);
if (group == NULL || CBS_len(params) != 0 ||
paramType == UNKNOWN_EC_PARAMETERS) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
goto err;
}
eckey = EC_KEY_new();
if (eckey == NULL || !EC_KEY_set_group(eckey, group)) {
goto err;
}
point = EC_POINT_new(group);
if (point == NULL ||
!EC_POINT_oct2point(group, point, CBS_data(key), CBS_len(key), NULL) ||
!EC_KEY_set_public_key(eckey, point)) {
goto err;
}
if(paramType == SPECIFIED_CURVE_EC_PARAMETERS) {
eckey->group_decoded_from_explicit_params = 1;
} else {
eckey->group_decoded_from_explicit_params = 0;
}
EC_POINT_free(point);
EVP_PKEY_assign_EC_KEY(out, eckey);
return 1;
err:
EC_POINT_free(point);
EC_KEY_free(eckey);
return 0;
}
static int eckey_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) {
int r;
const EC_GROUP *group = EC_KEY_get0_group(b->pkey.ec);
const EC_POINT *pa = EC_KEY_get0_public_key(a->pkey.ec),
*pb = EC_KEY_get0_public_key(b->pkey.ec);
r = EC_POINT_cmp(group, pa, pb, NULL);
if (r == 0) {
return 1;
} else if (r == 1) {
return 0;
} else {
return -2;
}
}
static int eckey_priv_decode(EVP_PKEY *out, CBS *oid, CBS *params, CBS *key, CBS *pubkey) {
// See RFC 5915.
if(pubkey) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return 0;
}
enum ECParametersType paramType = UNKNOWN_EC_PARAMETERS;
const EC_GROUP *group = EC_KEY_parse_parameters_and_type(params, &paramType);
if (group == NULL || CBS_len(params) != 0 || paramType == UNKNOWN_EC_PARAMETERS) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return 0;
}
EC_KEY *ec_key = EC_KEY_parse_private_key(key, group);
if (ec_key == NULL || CBS_len(key) != 0) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
EC_KEY_free(ec_key);
return 0;
}
if (paramType == SPECIFIED_CURVE_EC_PARAMETERS) {
ec_key->group_decoded_from_explicit_params = 1;
} else {
ec_key->group_decoded_from_explicit_params = 0;
}
EVP_PKEY_assign_EC_KEY(out, ec_key);
return 1;
}
static int eckey_priv_encode(CBB *out, const EVP_PKEY *key) {
const EC_KEY *ec_key = key->pkey.ec;
// Omit the redundant copy of the curve name. This contradicts RFC 5915 but
// aligns with PKCS #11. SEC 1 only says they may be omitted if known by other
// means. Both OpenSSL and NSS omit the redundant parameters, so we omit them
// as well.
unsigned enc_flags = EC_KEY_get_enc_flags(ec_key) | EC_PKEY_NO_PARAMETERS;
// See RFC 5915.
CBB pkcs8, algorithm, oid, private_key;
if (!CBB_add_asn1(out, &pkcs8, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1_uint64(&pkcs8, PKCS8_VERSION_ONE /* version */) ||
!CBB_add_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) ||
!CBB_add_bytes(&oid, ec_asn1_meth.oid, ec_asn1_meth.oid_len) ||
!EC_KEY_marshal_curve_name(&algorithm, EC_KEY_get0_group(ec_key)) ||
!CBB_add_asn1(&pkcs8, &private_key, CBS_ASN1_OCTETSTRING) ||
!EC_KEY_marshal_private_key(&private_key, ec_key, enc_flags) ||
!CBB_flush(out)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
return 0;
}
return 1;
}
static int int_ec_size(const EVP_PKEY *pkey) {
return ECDSA_size(pkey->pkey.ec);
}
static int ec_bits(const EVP_PKEY *pkey) {
const EC_GROUP *group = EC_KEY_get0_group(pkey->pkey.ec);
if (group == NULL) {
ERR_clear_error();
return 0;
}
return EC_GROUP_order_bits(group);
}
static int ec_missing_parameters(const EVP_PKEY *pkey) {
return pkey->pkey.ec == NULL || EC_KEY_get0_group(pkey->pkey.ec) == NULL;
}
static int ec_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from) {
if (from->pkey.ec == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NO_KEY_SET);
return 0;
}
const EC_GROUP *group = EC_KEY_get0_group(from->pkey.ec);
if (group == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_MISSING_PARAMETERS);
return 0;
}
if (to->pkey.ec == NULL) {
to->pkey.ec = EC_KEY_new();
if (to->pkey.ec == NULL) {
return 0;
}
}
return EC_KEY_set_group(to->pkey.ec, group);
}
static int ec_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b) {
if (a->pkey.ec == NULL || b->pkey.ec == NULL) {
return -2;
}
const EC_GROUP *group_a = EC_KEY_get0_group(a->pkey.ec),
*group_b = EC_KEY_get0_group(b->pkey.ec);
if (group_a == NULL || group_b == NULL) {
return -2;
}
if (EC_GROUP_cmp(group_a, group_b, NULL) != 0) {
// mismatch
return 0;
}
return 1;
}
static void int_ec_free(EVP_PKEY *pkey) { EC_KEY_free(pkey->pkey.ec); }
static int eckey_opaque(const EVP_PKEY *pkey) {
return EC_KEY_is_opaque(pkey->pkey.ec);
}
const EVP_PKEY_ASN1_METHOD ec_asn1_meth = {
EVP_PKEY_EC,
// 1.2.840.10045.2.1
{0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01}, 7,
"EC",
"OpenSSL EC algorithm",
eckey_pub_decode,
eckey_pub_encode,
eckey_pub_cmp,
eckey_priv_decode,
eckey_priv_encode,
NULL /* priv_encode_v2 */,
NULL /* set_priv_raw */,
NULL /* set_pub_raw */,
NULL /* get_priv_raw */,
NULL /* get_pub_raw */,
eckey_opaque,
int_ec_size,
ec_bits,
ec_missing_parameters,
ec_copy_parameters,
ec_cmp_parameters,
int_ec_free,
};

View File

@@ -0,0 +1,297 @@
// Copyright (c) 2017, Google Inc.
// SPDX-License-Identifier: ISC
#include <openssl/evp.h>
#include <openssl/bytestring.h>
#include <openssl/curve25519.h>
#include <openssl/err.h>
#include <openssl/mem.h>
#include "../fipsmodule/evp/internal.h"
#include "../internal.h"
#include "internal.h"
static void ed25519_free(EVP_PKEY *pkey) {
OPENSSL_free(pkey->pkey.ptr);
pkey->pkey.ptr = NULL;
}
static int ed25519_set_priv_raw(EVP_PKEY *pkey, const uint8_t *privkey,
size_t privkey_len, const uint8_t *pubkey,
size_t pubkey_len) {
if (privkey_len != ED25519_PRIVATE_KEY_SEED_LEN) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return 0;
}
if(pubkey && pubkey_len != ED25519_PUBLIC_KEY_LEN) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return 0;
}
ED25519_KEY *key = OPENSSL_malloc(sizeof(ED25519_KEY));
if (key == NULL) {
return 0;
}
// The RFC 8032 encoding stores only the 32-byte seed, so we must recover the
// full representation which we use from it.
uint8_t pubkey_computed[ED25519_PUBLIC_KEY_LEN];
ED25519_keypair_from_seed(pubkey_computed, key->key, privkey);
key->has_private = 1;
// If a public key was provided, validate that it matches the computed value.
if(pubkey && OPENSSL_memcmp(pubkey_computed, pubkey, pubkey_len) != 0) {
OPENSSL_free(key);
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return 0;
}
ed25519_free(pkey);
pkey->pkey.ptr = key;
return 1;
}
static int ed25519_set_pub_raw(EVP_PKEY *pkey, const uint8_t *in, size_t len) {
if (len != ED25519_PUBLIC_KEY_LEN) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return 0;
}
ED25519_KEY *key = OPENSSL_malloc(sizeof(ED25519_KEY));
if (key == NULL) {
return 0;
}
OPENSSL_memcpy(key->key + ED25519_PUBLIC_KEY_OFFSET, in, ED25519_PUBLIC_KEY_LEN);
key->has_private = 0;
ed25519_free(pkey);
pkey->pkey.ptr = key;
return 1;
}
static int ed25519_get_priv_raw(const EVP_PKEY *pkey, uint8_t *out,
size_t *out_len) {
const ED25519_KEY *key = pkey->pkey.ptr;
if (!key->has_private) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY);
return 0;
}
if (out == NULL) {
*out_len = ED25519_PRIVATE_KEY_SEED_LEN;
return 1;
}
if (*out_len < 32) {
OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
return 0;
}
// The raw private key format is the first 32 bytes of the private key.
OPENSSL_memcpy(out, key->key, ED25519_PRIVATE_KEY_SEED_LEN);
*out_len = 32;
return 1;
}
static int ed25519_get_pub_raw(const EVP_PKEY *pkey, uint8_t *out,
size_t *out_len) {
const ED25519_KEY *key = pkey->pkey.ptr;
if (out == NULL) {
*out_len = ED25519_PUBLIC_KEY_LEN;
return 1;
}
if (*out_len < ED25519_PUBLIC_KEY_LEN) {
OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
return 0;
}
OPENSSL_memcpy(out, key->key + ED25519_PUBLIC_KEY_OFFSET, ED25519_PUBLIC_KEY_LEN);
*out_len = 32;
return 1;
}
static int ed25519_pub_decode(EVP_PKEY *out, CBS *oid, CBS *params, CBS *key) {
// See RFC 8410, section 4.
// The parameters must be omitted. Public keys have length 32.
if (CBS_len(params) != 0) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return 0;
}
return ed25519_set_pub_raw(out, CBS_data(key), CBS_len(key));
}
static int ed25519_pub_encode(CBB *out, const EVP_PKEY *pkey) {
const ED25519_KEY *key = pkey->pkey.ptr;
// See RFC 8410, section 4.
CBB spki, algorithm, oid, key_bitstring;
if (!CBB_add_asn1(out, &spki, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) ||
!CBB_add_bytes(&oid, ed25519_asn1_meth.oid, ed25519_asn1_meth.oid_len) ||
!CBB_add_asn1(&spki, &key_bitstring, CBS_ASN1_BITSTRING) ||
!CBB_add_u8(&key_bitstring, 0 /* padding */) ||
!CBB_add_bytes(&key_bitstring, key->key + ED25519_PUBLIC_KEY_OFFSET,
32) ||
!CBB_flush(out)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
return 0;
}
return 1;
}
static int ed25519_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) {
const ED25519_KEY *a_key = a->pkey.ptr;
const ED25519_KEY *b_key = b->pkey.ptr;
return OPENSSL_memcmp(a_key->key + ED25519_PUBLIC_KEY_OFFSET,
b_key->key + ED25519_PUBLIC_KEY_OFFSET, ED25519_PUBLIC_KEY_LEN) == 0;
}
static int ed25519_priv_decode(EVP_PKEY *out, CBS *oid, CBS *params, CBS *key, CBS *pubkey) {
// See RFC 8410, section 7.
// Parameters must be empty. The key is a 32-byte value wrapped in an extra
// OCTET STRING layer.
CBS inner;
if (CBS_len(params) != 0 ||
!CBS_get_asn1(key, &inner, CBS_ASN1_OCTETSTRING) ||
CBS_len(key) != 0) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return 0;
}
const uint8_t *public= NULL;
size_t public_len = 0;
if (pubkey) {
// pubkey is encoded as an ASN.1 BIT STRING, so we handle the padding here
// byte here.
uint8_t padding;
if (!CBS_get_u8(pubkey, &padding) || padding != 0) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return 0;
}
public = CBS_data(pubkey);
public_len = CBS_len(pubkey);
}
return ed25519_set_priv_raw(out, CBS_data(&inner), CBS_len(&inner), public, public_len);
}
static int ed25519_priv_encode(CBB *out, const EVP_PKEY *pkey) {
ED25519_KEY *key = pkey->pkey.ptr;
if (!key->has_private) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY);
return 0;
}
// See RFC 8410, section 7.
CBB pkcs8, algorithm, oid, private_key, inner;
if (!CBB_add_asn1(out, &pkcs8, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1_uint64(&pkcs8, PKCS8_VERSION_ONE /* version */) ||
!CBB_add_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) ||
!CBB_add_bytes(&oid, ed25519_asn1_meth.oid, ed25519_asn1_meth.oid_len) ||
!CBB_add_asn1(&pkcs8, &private_key, CBS_ASN1_OCTETSTRING) ||
!CBB_add_asn1(&private_key, &inner, CBS_ASN1_OCTETSTRING) ||
// The PKCS#8 encoding stores only the 32-byte seed which is the first 32
// bytes of the private key.
!CBB_add_bytes(&inner, key->key, 32) ||
!CBB_flush(out)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
return 0;
}
return 1;
}
static int ed25519_priv_encode_v2(CBB *out, const EVP_PKEY *pkey) {
ED25519_KEY *key = pkey->pkey.ptr;
if (!key->has_private) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY);
return 0;
}
// See RFC 8410, section 7.
CBB pkcs8, algorithm, oid, private_key, inner, public_key;
if (!CBB_add_asn1(out, &pkcs8, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1_uint64(&pkcs8, PKCS8_VERSION_TWO /* version */) ||
!CBB_add_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) ||
!CBB_add_bytes(&oid, ed25519_asn1_meth.oid, ed25519_asn1_meth.oid_len) ||
!CBB_add_asn1(&pkcs8, &private_key, CBS_ASN1_OCTETSTRING) ||
!CBB_add_asn1(&private_key, &inner, CBS_ASN1_OCTETSTRING) ||
// The PKCS#8 encoding stores only the 32-byte seed which is the first 32
// bytes of the private key.
!CBB_add_bytes(&inner, key->key, ED25519_PRIVATE_KEY_SEED_LEN) ||
!CBB_add_asn1(&pkcs8, &public_key, CBS_ASN1_CONTEXT_SPECIFIC | 1) ||
!CBB_add_u8(&public_key, 0 /*no padding required*/) ||
// The last 32-bytes of the key is the public key
!CBB_add_bytes(&public_key, &key->key[32], ED25519_PUBLIC_KEY_LEN) || !CBB_flush(out)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
return 0;
}
return 1;
}
static int ed25519_size(const EVP_PKEY *pkey) { return 64; }
static int ed25519_bits(const EVP_PKEY *pkey) { return 253; }
const EVP_PKEY_ASN1_METHOD ed25519_asn1_meth = {
EVP_PKEY_ED25519,
{0x2b, 0x65, 0x70},
3,
"ED25519",
"OpenSSL ED25519 algorithm",
ed25519_pub_decode,
ed25519_pub_encode,
ed25519_pub_cmp,
ed25519_priv_decode,
ed25519_priv_encode,
ed25519_priv_encode_v2,
ed25519_set_priv_raw,
ed25519_set_pub_raw,
ed25519_get_priv_raw,
ed25519_get_pub_raw,
NULL /* pkey_opaque */,
ed25519_size,
ed25519_bits,
NULL /* param_missing */,
NULL /* param_copy */,
NULL /* param_cmp */,
ed25519_free,
};
const EVP_PKEY_ASN1_METHOD ed25519ph_asn1_meth = {
EVP_PKEY_ED25519PH,
{0xFF}, /* oid */
0, /* oid_len */
"ED25519ph", /* pem_str */
"OpenSSL ED25519ph algorithm", /* info */
NULL, /* pub_decode */
NULL, /* pub_encode */
NULL, /* pub_cmp */
NULL, /* priv_decode */
NULL, /* priv_encode */
NULL, /* priv_encode_v2 */
ed25519_set_priv_raw,
ed25519_set_pub_raw,
ed25519_get_priv_raw,
ed25519_get_pub_raw,
NULL /* pkey_opaque */,
ed25519_size,
ed25519_bits,
NULL /* param_missing */,
NULL /* param_copy */,
NULL /* param_cmp */,
ed25519_free,
};

View File

@@ -0,0 +1,94 @@
// Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project 2007.
// Copyright (c) 2007 The OpenSSL Project. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
#include <openssl/digest.h>
#include <openssl/evp.h>
#include <openssl/mem.h>
#include "../internal.h"
#include "internal.h"
static int hmac_size(OPENSSL_UNUSED const EVP_PKEY *pkey) {
return EVP_MAX_MD_SIZE;
}
static void hmac_key_free(EVP_PKEY *pkey) {
HMAC_KEY *key = pkey->pkey.ptr;
if (key != NULL) {
OPENSSL_free(key->key);
}
OPENSSL_free(key);
}
static int hmac_set_key(EVP_PKEY *pkey, const uint8_t *priv, size_t len,
OPENSSL_UNUSED const uint8_t *pubkey,
OPENSSL_UNUSED size_t pubkey_len) {
if (pkey->pkey.ptr != NULL) {
return 0;
}
HMAC_KEY *key = HMAC_KEY_new();
if (key == NULL) {
return 0;
}
key->key = OPENSSL_memdup(priv, len);
if (key->key == NULL && len > 0) {
OPENSSL_free(key);
return 0;
}
key->key_len = len;
pkey->pkey.ptr = key;
return 1;
}
static int hmac_get_key(const EVP_PKEY *pkey, uint8_t *priv, size_t *len) {
HMAC_KEY *key = pkey->pkey.ptr;
if (key == NULL || len == NULL) {
return 0;
}
// The semantics of the EVP APIs are to return the length, if |priv| is NULL.
if (priv == NULL) {
*len = key->key_len;
return 1;
}
// Retrieve the key, if |*len| has a large enough length.
if (*len < key->key_len) {
return 0;
}
*len = key->key_len;
OPENSSL_memcpy(priv, key->key, key->key_len);
return 1;
}
const EVP_PKEY_ASN1_METHOD hmac_asn1_meth = {
EVP_PKEY_HMAC,
{0xff} /* placeholder oid */,
0 /* oid_len */,
"HMAC",
"OpenSSL HMAC method",
NULL /* pub_decode */,
NULL /* pub_encode */,
NULL /* pub_cmp */,
NULL /*priv_decode */,
NULL /* priv_encode */,
NULL /* priv_encode_v2 */,
hmac_set_key /* set_priv_raw */,
NULL /* set_pub_raw */,
hmac_get_key /* get_priv_raw */,
NULL /* get_pub_raw */,
NULL /* pkey_opaque */,
hmac_size /* pkey_size */,
NULL /* pkey_bits */,
NULL /* param_missing */,
NULL /* param_copy */,
NULL /* param_cmp */,
hmac_key_free /* pkey_free */
};

View File

@@ -0,0 +1,275 @@
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR ISC
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/mem.h>
#include <openssl/bytestring.h>
#include "../fipsmodule/evp/internal.h"
#include "../fipsmodule/kem/internal.h"
#include "../internal.h"
#include "internal.h"
static void kem_free(EVP_PKEY *pkey) {
KEM_KEY_free(pkey->pkey.kem_key);
pkey->pkey.kem_key = NULL;
}
static int kem_get_priv_raw(const EVP_PKEY *pkey, uint8_t *out,
size_t *out_len) {
if (pkey->pkey.kem_key == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET);
return 0;
}
KEM_KEY *key = pkey->pkey.kem_key;
const KEM *kem = key->kem;
if (kem == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET);
return 0;
}
if (out == NULL) {
*out_len = kem->secret_key_len;
return 1;
}
if (*out_len < kem->secret_key_len) {
OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
return 0;
}
if (key->secret_key == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NO_KEY_SET);
return 0;
}
OPENSSL_memcpy(out, key->secret_key, kem->secret_key_len);
*out_len = kem->secret_key_len;
return 1;
}
static int kem_get_pub_raw(const EVP_PKEY *pkey, uint8_t *out,
size_t *out_len) {
if (pkey->pkey.kem_key == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET);
return 0;
}
KEM_KEY *key = pkey->pkey.kem_key;
const KEM *kem = key->kem;
if (kem == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET);
return 0;
}
if (out == NULL) {
*out_len = kem->public_key_len;
return 1;
}
if (*out_len < kem->public_key_len) {
OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
return 0;
}
if (key->public_key == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NO_KEY_SET);
return 0;
}
OPENSSL_memcpy(out, key->public_key, kem->public_key_len);
*out_len = kem->public_key_len;
return 1;
}
static int kem_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b) {
const KEM_KEY *a_key = a->pkey.kem_key;
const KEM_KEY *b_key = b->pkey.kem_key;
if (a_key == NULL || b_key == NULL) {
return -2;
}
const KEM *a_kem = a_key->kem;
const KEM *b_kem = b_key->kem;
if (a_kem == NULL || b_kem == NULL) {
return -2;
}
return a_kem->nid == b_kem->nid;
}
static int kem_pub_decode(EVP_PKEY *out, CBS *oid, CBS *params, CBS *key) {
// See https://datatracker.ietf.org/doc/draft-ietf-lamps-kyber-certificates/
// section 4. There should be no parameters
if (CBS_len(params) > 0) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return 0;
}
// Set the kem params on |out|.
if (!EVP_PKEY_kem_set_params(out, OBJ_cbs2nid(oid))) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return 0;
}
if (CBS_len(key) != out->pkey.kem_key->kem->public_key_len) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_BUFFER_SIZE);
return 0;
}
return KEM_KEY_set_raw_public_key(out->pkey.kem_key, CBS_data(key));
}
static int kem_pub_encode(CBB *out, const EVP_PKEY *pkey) {
KEM_KEY *key = pkey->pkey.kem_key;
const KEM *kem = key->kem;
if (key->public_key == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
return 0;
}
// See https://datatracker.ietf.org/doc/draft-ietf-lamps-kyber-certificates/
// section 4.
CBB spki, algorithm, oid, key_bitstring;
if (!CBB_add_asn1(out, &spki, CBS_ASN1_SEQUENCE) || // SubjectPublicKeyInfo SEQUENCE
!CBB_add_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) || // algorithm: AlgorithmIdentifier SEQUENCE
!CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) || // OBJECT IDENTIFIER
!CBB_add_bytes(&oid, kem->oid, kem->oid_len) || // OID bytes for id-alg-ml-kem-512/768/1024, params must be absent per standard
!CBB_add_asn1(&spki, &key_bitstring, CBS_ASN1_BITSTRING) || // subjectPublicKey: BIT STRING
!CBB_add_u8(&key_bitstring, 0 /* padding */) || // 0 unused bits (ML-KEM public keys are complete octets)
!CBB_add_bytes(&key_bitstring, key->public_key, kem->public_key_len) || // Raw ML-KEM public key
!CBB_flush(out)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
return 0;
}
return 1;
}
static int kem_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) {
int ret;
ret = kem_cmp_parameters(a, b);
if (ret <= 0) {
return ret;
}
const KEM_KEY *a_key = a->pkey.kem_key;
const KEM_KEY *b_key = b->pkey.kem_key;
return OPENSSL_memcmp(a_key->public_key, b_key->public_key,
a_key->kem->public_key_len) == 0;
}
static int kem_priv_decode(EVP_PKEY *out, CBS *oid, CBS *params, CBS *key,
CBS *pubkey) {
// See https://datatracker.ietf.org/doc/draft-ietf-lamps-kyber-certificates/
// section 6. There should be no parameters.
if (CBS_len(params) > 0) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return 0;
}
// Set the kem params on |out|.
if (!EVP_PKEY_kem_set_params(out, OBJ_cbs2nid(oid))) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return 0;
}
// Support multiple ML-KEM private key formats from
// https://datatracker.ietf.org/doc/draft-ietf-lamps-kyber-certificates/
// Case 1: seed [0] OCTET STRING
// Case 2: expandedKey OCTET STRING
// Case 3: TODO: both SEQUENCE {seed, expandedKey}
if (CBS_peek_asn1_tag(key, CBS_ASN1_CONTEXT_SPECIFIC)) {
// Case 1: seed [0] OCTET STRING
CBS seed;
if (!CBS_get_asn1(key, &seed, CBS_ASN1_CONTEXT_SPECIFIC)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return 0;
}
if (CBS_len(&seed) != out->pkey.kem_key->kem->keygen_seed_len) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_BUFFER_SIZE);
return 0;
}
return KEM_KEY_set_raw_keypair_from_seed(out->pkey.kem_key, &seed);
} else if (CBS_peek_asn1_tag(key, CBS_ASN1_OCTETSTRING)) {
// Case 2: expandedKey OCTET STRING
CBS expanded_key;
if (!CBS_get_asn1(key, &expanded_key, CBS_ASN1_OCTETSTRING)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return 0;
}
if (CBS_len(&expanded_key) != out->pkey.kem_key->kem->secret_key_len) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_BUFFER_SIZE);
return 0;
}
return KEM_KEY_set_raw_secret_key(out->pkey.kem_key, CBS_data(&expanded_key));
} else {
// Case 3: both SEQUENCE {seed, expandedKey} - not implemented yet
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return 0;
}
}
static int kem_priv_encode(CBB *out, const EVP_PKEY *pkey) {
KEM_KEY *key = pkey->pkey.kem_key;
const KEM *kem = key->kem;
if (key->secret_key == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY);
return 0;
}
// See https://datatracker.ietf.org/doc/draft-ietf-lamps-kyber-certificates/
// section 6.
CBB pkcs8, algorithm, oid, private_key, expanded_key;
if (!CBB_add_asn1(out, &pkcs8, CBS_ASN1_SEQUENCE) || // OneAsymmetricKey SEQUENCE
!CBB_add_asn1_uint64(&pkcs8, PKCS8_VERSION_ONE /* version */) ||
!CBB_add_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) || // privateKeyAlgorithm: SEQUENCE
!CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) || // algorithm: OBJECT IDENTIFIER
!CBB_add_bytes(&oid, kem->oid, kem->oid_len) || // OID bytes for id-alg-ml-kem-512/768/1024
!CBB_add_asn1(&pkcs8, &private_key, CBS_ASN1_OCTETSTRING) || // // privateKey: OCTET STRING (outer container)
!CBB_add_asn1(&private_key, &expanded_key, CBS_ASN1_OCTETSTRING) || // expandedKey CHOICE variant, AWS-LC uses expandedKey for the moment
!CBB_add_bytes(&expanded_key, key->secret_key, kem->secret_key_len) || // raw private key
!CBB_flush(out)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
return 0;
}
return 1;
}
const EVP_PKEY_ASN1_METHOD kem_asn1_meth = {
// 2.16.840.1.101.3.4.4
EVP_PKEY_KEM,
{0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x04},
8,
"KEM",
"AWS-LC KEM method",
kem_pub_decode,
kem_pub_encode,
kem_pub_cmp,
kem_priv_decode,
kem_priv_encode,
NULL, // priv_encode_v2
NULL, // kem_set_priv_raw
NULL, // kem_set_pub_raw
kem_get_priv_raw,
kem_get_pub_raw,
NULL, // pkey_opaque
NULL, // kem_size
NULL, // kem_bits
NULL, // param_missing
NULL, // param_copy
kem_cmp_parameters,
kem_free,
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,44 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR ISC
#include <openssl/base.h>
#include "../fipsmodule/evp/internal.h"
#include "../internal.h"
#include "internal.h"
static const EVP_PKEY_METHOD *const non_fips_pkey_evp_methods[] = {
&x25519_pkey_meth,
&dh_pkey_meth,
&dsa_pkey_meth
};
const EVP_PKEY_ASN1_METHOD *const asn1_evp_pkey_methods[] = {
&rsa_asn1_meth,
&rsa_pss_asn1_meth,
&ec_asn1_meth,
&dsa_asn1_meth,
&ed25519_asn1_meth,
&x25519_asn1_meth,
&pqdsa_asn1_meth,
&kem_asn1_meth,
&hmac_asn1_meth,
&dh_asn1_meth,
&ed25519ph_asn1_meth
};
const size_t asn1_evp_pkey_methods_size = sizeof(asn1_evp_pkey_methods)/sizeof(asn1_evp_pkey_methods[0]);
OPENSSL_STATIC_ASSERT(
NON_FIPS_EVP_PKEY_METHODS == OPENSSL_ARRAY_SIZE(non_fips_pkey_evp_methods),
NON_FIPS_EVP_PKEY_METHODS_does_not_have_the_expected_value)
OPENSSL_STATIC_ASSERT(
ASN1_EVP_PKEY_METHODS == OPENSSL_ARRAY_SIZE(asn1_evp_pkey_methods),
ASN1_EVP_PKEY_METHODS_does_not_have_the_expected_value)
const EVP_PKEY_METHOD *const *AWSLC_non_fips_pkey_evp_methods(void) {
return non_fips_pkey_evp_methods;
}
const EVP_PKEY_ASN1_METHOD *const *AWSLC_non_fips_pkey_evp_asn1_methods(void) {
return asn1_evp_pkey_methods;
}

View File

@@ -0,0 +1,276 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR ISC
#include <openssl/evp.h>
#include <openssl/bytestring.h>
#include <openssl/err.h>
#include <openssl/mem.h>
#include "../crypto/fipsmodule/pqdsa/internal.h"
#include "../crypto/internal.h"
#include "../fipsmodule/evp/internal.h"
#include "../fipsmodule/ml_dsa/ml_dsa.h"
#include "internal.h"
static void pqdsa_free(EVP_PKEY *pkey) {
PQDSA_KEY_free(pkey->pkey.pqdsa_key);
pkey->pkey.pqdsa_key = NULL;
}
static int pqdsa_get_priv_raw(const EVP_PKEY *pkey, uint8_t *out,
size_t *out_len) {
GUARD_PTR(pkey);
GUARD_PTR(out_len);
if (pkey->pkey.pqdsa_key == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET);
return 0;
}
PQDSA_KEY *key = pkey->pkey.pqdsa_key;
const PQDSA *pqdsa = key->pqdsa;
if (key->private_key == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY);
return 0;
}
if (pqdsa == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET);
return 0;
}
if (out == NULL) {
*out_len = key->pqdsa->private_key_len;
return 1;
}
if (*out_len < key->pqdsa->private_key_len) {
OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
return 0;
}
OPENSSL_memcpy(out, key->private_key, pqdsa->private_key_len);
*out_len = pqdsa->private_key_len;
return 1;
}
static int pqdsa_get_pub_raw(const EVP_PKEY *pkey, uint8_t *out,
size_t *out_len) {
if (pkey->pkey.pqdsa_key == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET);
return 0;
}
PQDSA_KEY *key = pkey->pkey.pqdsa_key;
const PQDSA *pqdsa = key->pqdsa;
if (pqdsa == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET);
return 0;
}
if (key->public_key == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
return 0;
}
if (out == NULL) {
*out_len = pqdsa->public_key_len;
return 1;
}
if (*out_len < key->pqdsa->public_key_len) {
OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
return 0;
}
OPENSSL_memcpy(out, key->public_key, pqdsa->public_key_len);
*out_len = pqdsa->public_key_len;
return 1;
}
static int pqdsa_pub_decode(EVP_PKEY *out, CBS *oid, CBS *params, CBS *key) {
// See https://datatracker.ietf.org/doc/draft-ietf-lamps-dilithium-certificates/
// section 4. There should be no parameters
if (CBS_len(params) > 0) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return 0;
}
// Set the pqdsa params on |out|.
if (!EVP_PKEY_pqdsa_set_params(out, OBJ_cbs2nid(oid))) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return 0;
}
return PQDSA_KEY_set_raw_public_key(out->pkey.pqdsa_key, key);
}
static int pqdsa_pub_encode(CBB *out, const EVP_PKEY *pkey) {
PQDSA_KEY *key = pkey->pkey.pqdsa_key;
const PQDSA *pqdsa = key->pqdsa;
if (key->public_key == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
return 0;
}
// See https://datatracker.ietf.org/doc/draft-ietf-lamps-dilithium-certificates/ section 4.
CBB spki, algorithm, oid, key_bitstring;
if (!CBB_add_asn1(out, &spki, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) ||
!CBB_add_bytes(&oid, pqdsa->oid, pqdsa->oid_len) ||
!CBB_add_asn1(&spki, &key_bitstring, CBS_ASN1_BITSTRING) ||
!CBB_add_u8(&key_bitstring, 0 /* padding */) ||
!CBB_add_bytes(&key_bitstring, key->public_key, pqdsa->public_key_len) ||
!CBB_flush(out)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
return 0;
}
return 1;
}
static int pqdsa_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) {
PQDSA_KEY *a_key = a->pkey.pqdsa_key;
PQDSA_KEY *b_key = b->pkey.pqdsa_key;
return OPENSSL_memcmp(a_key->public_key,
b_key->public_key,
a->pkey.pqdsa_key->pqdsa->public_key_len) == 0;
}
static int pqdsa_priv_decode(EVP_PKEY *out, CBS *oid, CBS *params, CBS *key, CBS *pubkey) {
// See https://datatracker.ietf.org/doc/draft-ietf-lamps-dilithium-certificates/
// section 6. There should be no parameters.
if (CBS_len(params) > 0) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return 0;
}
// Set the pqdsa params on |out|.
if (!EVP_PKEY_pqdsa_set_params(out, OBJ_cbs2nid(oid))) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return 0;
}
// Try to parse as one of the three ASN.1 formats defined in ML-DSA-XX-PrivateKey
// https://datatracker.ietf.org/doc/draft-ietf-lamps-dilithium-certificates/
// Case 1: seed [0] OCTET STRING
// Case 2: expandedKey OCTET STRING
// Case 3: both SEQUENCE {seed, expandedKey}
if (CBS_peek_asn1_tag(key, CBS_ASN1_CONTEXT_SPECIFIC | 0)) {
// Case 1: seed [0] OCTET STRING
CBS seed;
if (!CBS_get_asn1(key, &seed, CBS_ASN1_CONTEXT_SPECIFIC | 0)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return 0;
}
if (CBS_len(&seed) != out->pkey.pqdsa_key->pqdsa->keygen_seed_len) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_BUFFER_SIZE);
return 0;
}
return PQDSA_KEY_set_raw_keypair_from_seed(out->pkey.pqdsa_key, &seed);
} else if (CBS_peek_asn1_tag(key, CBS_ASN1_OCTETSTRING)) {
// Case 2: expandedKey OCTET STRING
CBS expanded_key;
if (!CBS_get_asn1(key, &expanded_key, CBS_ASN1_OCTETSTRING)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return 0;
}
if (CBS_len(&expanded_key) != out->pkey.pqdsa_key->pqdsa->private_key_len) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_BUFFER_SIZE);
return 0;
}
return PQDSA_KEY_set_raw_private_key(out->pkey.pqdsa_key, &expanded_key);
} else if (CBS_peek_asn1_tag(key, CBS_ASN1_SEQUENCE)) {
// Case 3: both SEQUENCE {seed, expandedKey}
CBS sequence, seed, expanded_key;
if (!CBS_get_asn1(key, &sequence, CBS_ASN1_SEQUENCE) ||
!CBS_get_asn1(&sequence, &seed, CBS_ASN1_OCTETSTRING) ||
!CBS_get_asn1(&sequence, &expanded_key, CBS_ASN1_OCTETSTRING)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return 0;
}
return PQDSA_KEY_set_raw_keypair_from_both(out->pkey.pqdsa_key, &seed, &expanded_key);
} else {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return 0;
}
}
static int pqdsa_priv_encode(CBB *out, const EVP_PKEY *pkey) {
PQDSA_KEY *key = pkey->pkey.pqdsa_key;
const PQDSA *pqdsa = key->pqdsa;
if (key->seed == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY);
return 0;
}
// See https://datatracker.ietf.org/doc/draft-ietf-lamps-dilithium-certificates/ section 6.
CBB pkcs8, algorithm, oid, private_key, seed_choice;
if (!CBB_add_asn1(out, &pkcs8, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1_uint64(&pkcs8, PKCS8_VERSION_ONE /* version */) ||
!CBB_add_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) ||
!CBB_add_bytes(&oid, pqdsa->oid, pqdsa->oid_len) ||
!CBB_add_asn1(&pkcs8, &private_key, CBS_ASN1_OCTETSTRING) ||
!CBB_add_asn1(&private_key, &seed_choice, CBS_ASN1_CONTEXT_SPECIFIC | 0) ||
!CBB_add_bytes(&seed_choice, key->seed, pqdsa->keygen_seed_len) ||
!CBB_flush(out)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
return 0;
}
return 1;
}
static int pqdsa_size(const EVP_PKEY *pkey) {
if (pkey->pkey.pqdsa_key == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET);
return 0;
}
return pkey->pkey.pqdsa_key->pqdsa->signature_len;
}
static int pqdsa_bits(const EVP_PKEY *pkey) {
if (pkey->pkey.pqdsa_key == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET);
return 0;
}
return 8 * (pkey->pkey.pqdsa_key->pqdsa->public_key_len);
}
const EVP_PKEY_ASN1_METHOD pqdsa_asn1_meth = {
//2.16.840.1.101.3.4.3
EVP_PKEY_PQDSA,
{0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03},
8,
"PQ DSA",
"AWS-LC PQ DSA method",
pqdsa_pub_decode,
pqdsa_pub_encode,
pqdsa_pub_cmp,
pqdsa_priv_decode,
pqdsa_priv_encode,
NULL /*priv_encode_v2*/,
NULL /* pqdsa_set_priv_raw */,
NULL /*pqdsa_set_pub_raw */ ,
pqdsa_get_priv_raw,
pqdsa_get_pub_raw,
NULL /* pkey_opaque */,
pqdsa_size,
pqdsa_bits,
NULL /* param_missing */,
NULL /* param_copy */,
NULL /* param_cmp */,
pqdsa_free,
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,228 @@
// Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project 2006.
// Copyright (c) 2006 The OpenSSL Project. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
#include <openssl/evp.h>
#include <openssl/bn.h>
#include <openssl/bytestring.h>
#include <openssl/digest.h>
#include <openssl/err.h>
#include <openssl/rsa.h>
#include "../rsa_extra/internal.h"
#include "../fipsmodule/evp/internal.h"
#include "../fipsmodule/rsa/internal.h"
#include "internal.h"
static int rsa_pub_encode(CBB *out, const EVP_PKEY *key) {
// See RFC 3279, section 2.3.1.
CBB spki, algorithm, oid, null, key_bitstring;
if (!CBB_add_asn1(out, &spki, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) ||
!CBB_add_bytes(&oid, rsa_asn1_meth.oid, rsa_asn1_meth.oid_len) ||
!CBB_add_asn1(&algorithm, &null, CBS_ASN1_NULL) ||
!CBB_add_asn1(&spki, &key_bitstring, CBS_ASN1_BITSTRING) ||
!CBB_add_u8(&key_bitstring, 0 /* padding */) ||
!RSA_marshal_public_key(&key_bitstring, key->pkey.rsa) ||
!CBB_flush(out)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
return 0;
}
return 1;
}
static int rsa_pub_decode(EVP_PKEY *out, CBS *oid, CBS *params, CBS *key) {
// The IETF specification defines that the parameters must be
// NULL. See RFC 3279, section 2.3.1.
// There is also an ITU-T X.509 specification that is rarely seen,
// which defines a KeySize parameter. See ITU-T X.509 2008-11
// AlgorithmObjectIdentifiers.
//
// OpenSSL ignores both parameters when parsing, however.
RSA *rsa = RSA_parse_public_key(key);
if (rsa == NULL || CBS_len(key) != 0) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
RSA_free(rsa);
return 0;
}
EVP_PKEY_assign_RSA(out, rsa);
return 1;
}
static int rsa_pss_pub_decode(EVP_PKEY *out, CBS *oid, CBS *params, CBS *key) {
RSASSA_PSS_PARAMS *pss = NULL;
if (!RSASSA_PSS_parse_params(params, &pss)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return 0;
}
RSA *rsa = RSA_parse_public_key(key);
if (rsa != NULL) {
rsa->pss = pss;
} else {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
RSASSA_PSS_PARAMS_free(pss);
return 0;
}
if (rsa == NULL ||
CBS_len(key) != 0 ||
!EVP_PKEY_assign(out, EVP_PKEY_RSA_PSS, rsa)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
RSA_free(rsa);
return 0;
}
return 1;
}
static int rsa_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) {
return BN_cmp(b->pkey.rsa->n, a->pkey.rsa->n) == 0 &&
BN_cmp(b->pkey.rsa->e, a->pkey.rsa->e) == 0;
}
static int rsa_priv_encode(CBB *out, const EVP_PKEY *key) {
CBB pkcs8, algorithm, oid, null, private_key;
if (!CBB_add_asn1(out, &pkcs8, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1_uint64(&pkcs8, PKCS8_VERSION_ONE /* version */) ||
!CBB_add_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) ||
!CBB_add_bytes(&oid, rsa_asn1_meth.oid, rsa_asn1_meth.oid_len) ||
!CBB_add_asn1(&algorithm, &null, CBS_ASN1_NULL) ||
!CBB_add_asn1(&pkcs8, &private_key, CBS_ASN1_OCTETSTRING) ||
!RSA_marshal_private_key(&private_key, key->pkey.rsa) ||
!CBB_flush(out)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
return 0;
}
return 1;
}
static int rsa_priv_decode(EVP_PKEY *out, CBS *oid, CBS *params, CBS *key, CBS *pubkey) {
if(pubkey) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return 0;
}
// Per RFC 8017, A.1, the parameters have type NULL.
CBS null;
if (!CBS_get_asn1(params, &null, CBS_ASN1_NULL) ||
CBS_len(&null) != 0 ||
CBS_len(params) != 0) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return 0;
}
RSA *rsa = RSA_parse_private_key(key);
if (rsa == NULL || CBS_len(key) != 0) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
RSA_free(rsa);
return 0;
}
EVP_PKEY_assign_RSA(out, rsa);
return 1;
}
static int rsa_pss_priv_decode(EVP_PKEY *out, CBS *oid, CBS *params, CBS *key, CBS *pubkey) {
RSASSA_PSS_PARAMS *pss = NULL;
if (!RSASSA_PSS_parse_params(params, &pss)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return 0;
}
RSA *rsa = RSA_parse_private_key(key);
if (rsa != NULL) {
rsa->pss = pss;
} else {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
RSASSA_PSS_PARAMS_free(pss);
return 0;
}
if (rsa == NULL ||
CBS_len(key) != 0 ||
!EVP_PKEY_assign(out, EVP_PKEY_RSA_PSS, rsa)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
RSA_free(rsa);
return 0;
}
return 1;
}
static int rsa_opaque(const EVP_PKEY *pkey) {
return RSA_is_opaque(pkey->pkey.rsa);
}
static int int_rsa_size(const EVP_PKEY *pkey) {
return RSA_size(pkey->pkey.rsa);
}
static int rsa_bits(const EVP_PKEY *pkey) {
return RSA_bits(pkey->pkey.rsa);
}
static void int_rsa_free(EVP_PKEY *pkey) { RSA_free(pkey->pkey.rsa); }
const EVP_PKEY_ASN1_METHOD rsa_asn1_meth = {
EVP_PKEY_RSA,
// 1.2.840.113549.1.1.1
{0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01}, 9,
"RSA",
"OpenSSL RSA method",
rsa_pub_decode,
rsa_pub_encode,
rsa_pub_cmp,
rsa_priv_decode,
rsa_priv_encode,
NULL /* priv_encode_v2 */,
NULL /* set_priv_raw */,
NULL /* set_pub_raw */,
NULL /* get_priv_raw */,
NULL /* get_pub_raw */,
rsa_opaque,
int_rsa_size,
rsa_bits,
0,0,0,
int_rsa_free,
};
const EVP_PKEY_ASN1_METHOD rsa_pss_asn1_meth = {
EVP_PKEY_RSA_PSS,
// 1.2.840.113549.1.1.10
{0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0a}, 9,
"RSA-PSS",
"OpenSSL RSA-PSS method",
rsa_pss_pub_decode,
NULL /* pub_encode */,
rsa_pub_cmp,
rsa_pss_priv_decode,
NULL /* priv_encode */,
NULL /* priv_encode_v2 */,
NULL /* set_priv_raw */,
NULL /* set_pub_raw */,
NULL /* get_priv_raw */,
NULL /* get_pub_raw */,
rsa_opaque,
int_rsa_size,
rsa_bits,
0,0,0,
int_rsa_free,
};

View File

@@ -0,0 +1,103 @@
// Copyright (c) 2019, Google Inc.
// SPDX-License-Identifier: ISC
#include <openssl/evp.h>
#include <openssl/curve25519.h>
#include <openssl/err.h>
#include <openssl/mem.h>
#include "../fipsmodule/evp/internal.h"
#include "internal.h"
// X25519 has no parameters to copy.
static int pkey_x25519_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) { return 1; }
static int pkey_x25519_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) {
X25519_KEY *key = OPENSSL_malloc(sizeof(X25519_KEY));
if (key == NULL) {
return 0;
}
evp_pkey_set_method(pkey, &x25519_asn1_meth);
X25519_keypair(key->pub, key->priv);
key->has_private = 1;
OPENSSL_free(pkey->pkey.ptr);
pkey->pkey.ptr = key;
return 1;
}
static int pkey_x25519_derive(EVP_PKEY_CTX *ctx, uint8_t *out,
size_t *out_len) {
if (ctx->pkey == NULL || ctx->peerkey == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_KEYS_NOT_SET);
return 0;
}
const X25519_KEY *our_key = ctx->pkey->pkey.ptr;
const X25519_KEY *peer_key = ctx->peerkey->pkey.ptr;
if (our_key == NULL || peer_key == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_KEYS_NOT_SET);
return 0;
}
if (!our_key->has_private) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY);
return 0;
}
if (out != NULL) {
if (*out_len < 32) {
OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
return 0;
}
if (!X25519(out, our_key->priv, peer_key->pub)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PEER_KEY);
return 0;
}
}
*out_len = 32;
return 1;
}
static int pkey_x25519_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) {
switch (type) {
case EVP_PKEY_CTRL_PEER_KEY:
// |EVP_PKEY_derive_set_peer| requires the key implement this command,
// even if it is a no-op.
return 1;
default:
OPENSSL_PUT_ERROR(EVP, EVP_R_COMMAND_NOT_SUPPORTED);
return 0;
}
}
const EVP_PKEY_METHOD x25519_pkey_meth = {
EVP_PKEY_X25519,
NULL /* init */,
pkey_x25519_copy,
NULL /* cleanup */,
pkey_x25519_keygen,
NULL /* sign_init */,
NULL /* sign */,
NULL /* sign_message */,
NULL /* verify_init */,
NULL /* verify */,
NULL /* verify_message */,
NULL /* verify_recover */,
NULL /* encrypt */,
NULL /* decrypt */,
pkey_x25519_derive,
NULL /* paramgen */,
pkey_x25519_ctrl,
NULL, /* ctrl_str */
NULL /* keygen deterministic */,
NULL /* encapsulate deterministic */,
NULL /* encapsulate */,
NULL /* decapsulate */,
};

View File

@@ -0,0 +1,265 @@
// Copyright (c) 2019, Google Inc.
// SPDX-License-Identifier: ISC
#include <openssl/evp.h>
#include <openssl/bytestring.h>
#include <openssl/curve25519.h>
#include <openssl/err.h>
#include <openssl/mem.h>
#include "../fipsmodule/evp/internal.h"
#include "../internal.h"
#include "internal.h"
static void x25519_free(EVP_PKEY *pkey) {
OPENSSL_free(pkey->pkey.ptr);
pkey->pkey.ptr = NULL;
}
static int x25519_set_priv_raw(EVP_PKEY *pkey, const uint8_t *privkey, size_t privkey_len, const uint8_t* pubkey, size_t pubkey_len) {
if (privkey_len != X25519_PRIVATE_KEY_LEN) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return 0;
}
if (pubkey && pubkey_len != X25519_PUBLIC_VALUE_LEN) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return 0;
}
X25519_KEY *key = OPENSSL_malloc(sizeof(X25519_KEY));
if (key == NULL) {
return 0;
}
OPENSSL_memcpy(key->priv, privkey, X25519_PRIVATE_KEY_LEN);
X25519_public_from_private(key->pub, key->priv);
key->has_private = 1;
// If a public key was provided, validate that it matches the computed value.
if(pubkey && OPENSSL_memcmp(key->pub, pubkey, pubkey_len) != 0) {
OPENSSL_free(key);
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return 0;
}
x25519_free(pkey);
pkey->pkey.ptr = key;
return 1;
}
static int x25519_set_pub_raw(EVP_PKEY *pkey, const uint8_t *in, size_t len) {
if (len != 32) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return 0;
}
X25519_KEY *key = OPENSSL_malloc(sizeof(X25519_KEY));
if (key == NULL) {
return 0;
}
OPENSSL_memcpy(key->pub, in, 32);
key->has_private = 0;
x25519_free(pkey);
pkey->pkey.ptr = key;
return 1;
}
static int x25519_get_priv_raw(const EVP_PKEY *pkey, uint8_t *out,
size_t *out_len) {
const X25519_KEY *key = pkey->pkey.ptr;
if (!key->has_private) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY);
return 0;
}
if (out == NULL) {
*out_len = 32;
return 1;
}
if (*out_len < 32) {
OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
return 0;
}
OPENSSL_memcpy(out, key->priv, 32);
*out_len = 32;
return 1;
}
static int x25519_get_pub_raw(const EVP_PKEY *pkey, uint8_t *out,
size_t *out_len) {
const X25519_KEY *key = pkey->pkey.ptr;
if (out == NULL) {
*out_len = 32;
return 1;
}
if (*out_len < 32) {
OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
return 0;
}
OPENSSL_memcpy(out, key->pub, 32);
*out_len = 32;
return 1;
}
static int x25519_pub_decode(EVP_PKEY *out, CBS *oid, CBS *params, CBS *key) {
// See RFC 8410, section 4.
// The parameters must be omitted. Public keys have length 32.
if (CBS_len(params) != 0) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return 0;
}
return x25519_set_pub_raw(out, CBS_data(key), CBS_len(key));
}
static int x25519_pub_encode(CBB *out, const EVP_PKEY *pkey) {
const X25519_KEY *key = pkey->pkey.ptr;
// See RFC 8410, section 4.
CBB spki, algorithm, oid, key_bitstring;
if (!CBB_add_asn1(out, &spki, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) ||
!CBB_add_bytes(&oid, x25519_asn1_meth.oid, x25519_asn1_meth.oid_len) ||
!CBB_add_asn1(&spki, &key_bitstring, CBS_ASN1_BITSTRING) ||
!CBB_add_u8(&key_bitstring, 0 /* padding */) ||
!CBB_add_bytes(&key_bitstring, key->pub, 32) ||
!CBB_flush(out)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
return 0;
}
return 1;
}
static int x25519_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) {
const X25519_KEY *a_key = a->pkey.ptr;
const X25519_KEY *b_key = b->pkey.ptr;
return OPENSSL_memcmp(a_key->pub, b_key->pub, 32) == 0;
}
static int x25519_priv_decode(EVP_PKEY *out, CBS *oid, CBS *params, CBS *key, CBS *pubkey) {
// See RFC 8410, section 7.
// Parameters must be empty. The key is a 32-byte value wrapped in an extra
// OCTET STRING layer.
CBS inner;
if (CBS_len(params) != 0 ||
!CBS_get_asn1(key, &inner, CBS_ASN1_OCTETSTRING) ||
CBS_len(key) != 0) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return 0;
}
const uint8_t *public= NULL;
size_t public_len = 0;
if (pubkey) {
uint8_t padding;
if (!CBS_get_u8(pubkey, &padding) || padding != 0) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return 0;
}
public = CBS_data(pubkey);
public_len = CBS_len(pubkey);
}
return x25519_set_priv_raw(out, CBS_data(&inner), CBS_len(&inner), public, public_len);
}
static int x25519_priv_encode(CBB *out, const EVP_PKEY *pkey) {
X25519_KEY *key = pkey->pkey.ptr;
if (!key->has_private) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY);
return 0;
}
// See RFC 8410, section 7.
CBB pkcs8, algorithm, oid, private_key, inner;
if (!CBB_add_asn1(out, &pkcs8, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1_uint64(&pkcs8, PKCS8_VERSION_ONE /* version */) ||
!CBB_add_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) ||
!CBB_add_bytes(&oid, x25519_asn1_meth.oid, x25519_asn1_meth.oid_len) ||
!CBB_add_asn1(&pkcs8, &private_key, CBS_ASN1_OCTETSTRING) ||
!CBB_add_asn1(&private_key, &inner, CBS_ASN1_OCTETSTRING) ||
// The PKCS#8 encoding stores only the 32-byte seed which is the first 32
// bytes of the private key.
!CBB_add_bytes(&inner, key->priv, 32) ||
!CBB_flush(out)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
return 0;
}
return 1;
}
static int x25519_priv_encode_v2(CBB *out, const EVP_PKEY *pkey) {
X25519_KEY *key = pkey->pkey.ptr;
if (!key->has_private) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY);
return 0;
}
// See RFC 8410, section 7.
CBB pkcs8, algorithm, oid, private_key, inner, public_key;
if (!CBB_add_asn1(out, &pkcs8, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1_uint64(&pkcs8, PKCS8_VERSION_TWO /* version */) ||
!CBB_add_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) ||
!CBB_add_bytes(&oid, x25519_asn1_meth.oid, x25519_asn1_meth.oid_len) ||
!CBB_add_asn1(&pkcs8, &private_key, CBS_ASN1_OCTETSTRING) ||
!CBB_add_asn1(&private_key, &inner, CBS_ASN1_OCTETSTRING) ||
// The PKCS#8 encoding stores only the 32-byte seed which is the first 32
// bytes of the private key.
!CBB_add_bytes(&inner, key->priv, 32) ||
!CBB_add_asn1(&pkcs8, &public_key, CBS_ASN1_CONTEXT_SPECIFIC|1) ||
!CBB_add_u8(&public_key, 0 /*no padding required*/) ||
!CBB_add_bytes(&public_key, key->pub, 32) ||
!CBB_flush(out)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
return 0;
}
return 1;
}
static int x25519_size(const EVP_PKEY *pkey) { return 32; }
static int x25519_bits(const EVP_PKEY *pkey) { return 253; }
const EVP_PKEY_ASN1_METHOD x25519_asn1_meth = {
EVP_PKEY_X25519,
{0x2b, 0x65, 0x6e},
3,
"X25519",
"OpenSSL X25519 algorithm",
x25519_pub_decode,
x25519_pub_encode,
x25519_pub_cmp,
x25519_priv_decode,
x25519_priv_encode,
x25519_priv_encode_v2,
x25519_set_priv_raw,
x25519_set_pub_raw,
x25519_get_priv_raw,
x25519_get_pub_raw,
NULL /* pkey_opaque */,
x25519_size,
x25519_bits,
NULL /* param_missing */,
NULL /* param_copy */,
NULL /* param_cmp */,
x25519_free,
};

View File

@@ -0,0 +1,384 @@
// Copyright (c) 2006 The OpenSSL Project. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
#include <openssl/evp.h>
#include <openssl/bio.h>
#include <openssl/bn.h>
#include <openssl/dsa.h>
#include <openssl/ec.h>
#include <openssl/ec_key.h>
#include <openssl/mem.h>
#include <openssl/rsa.h>
#include "internal.h"
#include "../internal.h"
#include "../fipsmodule/evp/internal.h"
#include "../fipsmodule/rsa/internal.h"
#include "../fipsmodule/ml_dsa/ml_dsa.h"
#include "../fipsmodule/pqdsa/internal.h"
static int print_hex(BIO *bp, const uint8_t *data, size_t len, int off) {
for (size_t i = 0; i < len; i++) {
if ((i % 15) == 0) {
if (BIO_puts(bp, "\n") <= 0 || //
!BIO_indent(bp, off + 4, 128)) {
return 0;
}
}
if (BIO_printf(bp, "%02x%s", data[i], (i + 1 == len) ? "" : ":") <= 0) {
return 0;
}
}
if (BIO_write(bp, "\n", 1) <= 0) {
return 0;
}
return 1;
}
static int bn_print(BIO *bp, const char *name, const BIGNUM *num, int off) {
if (num == NULL) {
return 1;
}
if (!BIO_indent(bp, off, 128)) {
return 0;
}
if (BN_is_zero(num)) {
if (BIO_printf(bp, "%s 0\n", name) <= 0) {
return 0;
}
return 1;
}
uint64_t u64;
if (BN_get_u64(num, &u64)) {
const char *neg = BN_is_negative(num) ? "-" : "";
return BIO_printf(bp, "%s %s%" PRIu64 " (%s0x%" PRIx64 ")\n", name, neg,
u64, neg, u64) > 0;
}
if (BIO_printf(bp, "%s%s", name,
(BN_is_negative(num)) ? " (Negative)" : "") <= 0) {
return 0;
}
// Print |num| in hex, adding a leading zero, as in ASN.1, if the high bit
// is set.
//
// TODO(davidben): Do we need to do this? We already print "(Negative)" above
// and negative values are never valid in keys anyway.
size_t len = BN_num_bytes(num);
uint8_t *buf = OPENSSL_zalloc(len + 1);
if (buf == NULL) {
return 0;
}
BN_bn2bin(num, buf + 1);
int ret;
if (len > 0 && (buf[1] & 0x80) != 0) {
// Print the whole buffer.
ret = print_hex(bp, buf, len + 1, off);
} else {
// Skip the leading zero.
ret = print_hex(bp, buf + 1, len, off);
}
OPENSSL_free(buf);
return ret;
}
// RSA keys.
static int do_rsa_print(BIO *out, const RSA *rsa, int off,
int include_private) {
int mod_len = 0;
if (rsa->n != NULL) {
mod_len = BN_num_bits(rsa->n);
}
if (!BIO_indent(out, off, 128)) {
return 0;
}
const char *s, *str;
if (include_private && rsa->d) {
// AWS-LC supports only standard two-prime RSA. Print prime count for
// OpenSSL compatibility in key format output.
if (BIO_printf(out, "Private-Key: (%d bit, %d primes)\n", mod_len, 2) <= 0) {
return 0;
}
str = "modulus:";
s = "publicExponent:";
} else {
if (BIO_printf(out, "Public-Key: (%d bit)\n", mod_len) <= 0) {
return 0;
}
str = "Modulus:";
s = "Exponent:";
}
if (!bn_print(out, str, rsa->n, off) ||
!bn_print(out, s, rsa->e, off)) {
return 0;
}
if (include_private) {
if (!bn_print(out, "privateExponent:", rsa->d, off) ||
!bn_print(out, "prime1:", rsa->p, off) ||
!bn_print(out, "prime2:", rsa->q, off) ||
!bn_print(out, "exponent1:", rsa->dmp1, off) ||
!bn_print(out, "exponent2:", rsa->dmq1, off) ||
!bn_print(out, "coefficient:", rsa->iqmp, off)) {
return 0;
}
}
return 1;
}
static int rsa_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent) {
return do_rsa_print(bp, EVP_PKEY_get0_RSA(pkey), indent, 0);
}
static int rsa_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent) {
return do_rsa_print(bp, EVP_PKEY_get0_RSA(pkey), indent, 1);
}
// DSA keys.
static int do_dsa_print(BIO *bp, const DSA *x, int off, int ptype) {
const BIGNUM *priv_key = NULL;
if (ptype == 2) {
priv_key = DSA_get0_priv_key(x);
}
const BIGNUM *pub_key = NULL;
if (ptype > 0) {
pub_key = DSA_get0_pub_key(x);
}
const char *ktype = "DSA-Parameters";
if (ptype == 2) {
ktype = "Private-Key";
} else if (ptype == 1) {
ktype = "Public-Key";
}
if (!BIO_indent(bp, off, 128) ||
BIO_printf(bp, "%s: (%u bit)\n", ktype, BN_num_bits(DSA_get0_p(x))) <=
0 ||
// |priv_key| and |pub_key| may be NULL, in which case |bn_print| will
// silently skip them.
!bn_print(bp, "priv:", priv_key, off) ||
!bn_print(bp, "pub:", pub_key, off) ||
!bn_print(bp, "P:", DSA_get0_p(x), off) ||
!bn_print(bp, "Q:", DSA_get0_q(x), off) ||
!bn_print(bp, "G:", DSA_get0_g(x), off)) {
return 0;
}
return 1;
}
static int dsa_param_print(BIO *bp, const EVP_PKEY *pkey, int indent) {
return do_dsa_print(bp, EVP_PKEY_get0_DSA(pkey), indent, 0);
}
static int dsa_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent) {
return do_dsa_print(bp, EVP_PKEY_get0_DSA(pkey), indent, 1);
}
static int dsa_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent) {
return do_dsa_print(bp, EVP_PKEY_get0_DSA(pkey), indent, 2);
}
// EC keys.
static int do_EC_KEY_print(BIO *bp, const EC_KEY *x, int off, int ktype) {
const EC_GROUP *group;
if (x == NULL || (group = EC_KEY_get0_group(x)) == NULL) {
OPENSSL_PUT_ERROR(EVP, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
const char *ecstr;
if (ktype == 2) {
ecstr = "Private-Key";
} else if (ktype == 1) {
ecstr = "Public-Key";
} else {
ecstr = "ECDSA-Parameters";
}
if (!BIO_indent(bp, off, 128)) {
return 0;
}
int curve_name = EC_GROUP_get_curve_name(group);
if (BIO_printf(bp, "%s: (%s)\n", ecstr,
curve_name == NID_undef
? "unknown curve"
: EC_curve_nid2nist(curve_name)) <= 0) {
return 0;
}
if (ktype == 2) {
const BIGNUM *priv_key = EC_KEY_get0_private_key(x);
if (priv_key != NULL && //
!bn_print(bp, "priv:", priv_key, off)) {
return 0;
}
}
if (ktype > 0 && EC_KEY_get0_public_key(x) != NULL) {
uint8_t *pub = NULL;
size_t pub_len = EC_KEY_key2buf(x, EC_KEY_get_conv_form(x), &pub, NULL);
if (pub_len == 0) {
return 0;
}
int ret = BIO_indent(bp, off, 128) && //
BIO_puts(bp, "pub:") > 0 && //
print_hex(bp, pub, pub_len, off);
OPENSSL_free(pub);
if (!ret) {
return 0;
}
}
return 1;
}
static int eckey_param_print(BIO *bp, const EVP_PKEY *pkey, int indent) {
return do_EC_KEY_print(bp, EVP_PKEY_get0_EC_KEY(pkey), indent, 0);
}
static int eckey_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent) {
return do_EC_KEY_print(bp, EVP_PKEY_get0_EC_KEY(pkey), indent, 1);
}
static int eckey_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent) {
return do_EC_KEY_print(bp, EVP_PKEY_get0_EC_KEY(pkey), indent, 2);
}
// MLDSA keys.
static int do_mldsa_65_print(BIO *bp, const EVP_PKEY *pkey, int off, int ptype) {
if (pkey == NULL) {
OPENSSL_PUT_ERROR(EVP, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
if (!BIO_indent(bp, off, 128)) {
return 0;
}
const PQDSA *pqdsa = pkey->pkey.pqdsa_key->pqdsa;
int bit_len = 0;
if (ptype == 2) {
bit_len = pqdsa->private_key_len;
if (BIO_printf(bp, "Private-Key: (%d bit)\n", bit_len) <= 0) {
return 0;
}
print_hex(bp, pkey->pkey.pqdsa_key->private_key, bit_len, off);
} else {
bit_len = pqdsa->public_key_len;
if (BIO_printf(bp, "Public-Key: (%d bit)\n", bit_len) <= 0) {
return 0;
}
int ret = print_hex(bp, pkey->pkey.pqdsa_key->public_key, bit_len, off);
if (!ret) {
return 0;
}
}
return 1;
}
static int mldsa_65_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent) {
return do_mldsa_65_print(bp, pkey, indent, 1);
}
static int mldsa_65_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent) {
return do_mldsa_65_print(bp, pkey, indent, 2);
}
typedef struct {
int type;
int (*pub_print)(BIO *out, const EVP_PKEY *pkey, int indent);
int (*priv_print)(BIO *out, const EVP_PKEY *pkey, int indent);
int (*param_print)(BIO *out, const EVP_PKEY *pkey, int indent);
} EVP_PKEY_PRINT_METHOD;
static const EVP_PKEY_PRINT_METHOD kPrintMethods[] = {
{
EVP_PKEY_RSA,
rsa_pub_print,
rsa_priv_print,
NULL /* param_print */,
},
{
EVP_PKEY_DSA,
dsa_pub_print,
dsa_priv_print,
dsa_param_print,
},
{
EVP_PKEY_EC,
eckey_pub_print,
eckey_priv_print,
eckey_param_print,
},
{
EVP_PKEY_PQDSA,
mldsa_65_pub_print,
mldsa_65_priv_print,
NULL /* param_print */,
},
};
static size_t kPrintMethodsLen = OPENSSL_ARRAY_SIZE(kPrintMethods);
static const EVP_PKEY_PRINT_METHOD *find_method(int type) {
for (size_t i = 0; i < kPrintMethodsLen; i++) {
if (kPrintMethods[i].type == type) {
return &kPrintMethods[i];
}
}
return NULL;
}
static int print_unsupported(BIO *out, const EVP_PKEY *pkey, int indent,
const char *kstr) {
BIO_indent(out, indent, 128);
BIO_printf(out, "%s algorithm unsupported\n", kstr);
return 1;
}
int EVP_PKEY_print_public(BIO *out, const EVP_PKEY *pkey, int indent,
ASN1_PCTX *pctx) {
const EVP_PKEY_PRINT_METHOD *method = find_method(EVP_PKEY_id(pkey));
if (method != NULL && method->pub_print != NULL) {
return method->pub_print(out, pkey, indent);
}
return print_unsupported(out, pkey, indent, "Public Key");
}
int EVP_PKEY_print_private(BIO *out, const EVP_PKEY *pkey, int indent,
ASN1_PCTX *pctx) {
const EVP_PKEY_PRINT_METHOD *method = find_method(EVP_PKEY_id(pkey));
if (method != NULL && method->priv_print != NULL) {
return method->priv_print(out, pkey, indent);
}
return print_unsupported(out, pkey, indent, "Private Key");
}
int EVP_PKEY_print_params(BIO *out, const EVP_PKEY *pkey, int indent,
ASN1_PCTX *pctx) {
const EVP_PKEY_PRINT_METHOD *method = find_method(EVP_PKEY_id(pkey));
if (method != NULL && method->param_print != NULL) {
return method->param_print(out, pkey, indent);
}
return print_unsupported(out, pkey, indent, "Parameters");
}

View File

@@ -0,0 +1,216 @@
// Copyright 2015-2016 The OpenSSL Project Authors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
#include <openssl/evp.h>
#include <assert.h>
#include <openssl/err.h>
#include <openssl/mem.h>
#include <openssl/type_check.h>
#include "../internal.h"
// This file implements scrypt, described in RFC 7914.
//
// Note scrypt refers to both "blocks" and a "block size" parameter, r. These
// are two different notions of blocks. A Salsa20 block is 64 bytes long,
// represented in this implementation by 16 |uint32_t|s. |r| determines the
// number of 64-byte Salsa20 blocks in a scryptBlockMix block, which is 2 * |r|
// Salsa20 blocks. This implementation refers to them as Salsa20 blocks and
// scrypt blocks, respectively.
// A block_t is a Salsa20 block.
#define SCRYPT_BLOCK_WORD_CNT 16
typedef struct { uint32_t words[SCRYPT_BLOCK_WORD_CNT]; } block_t;
OPENSSL_STATIC_ASSERT(sizeof(block_t) == 64, block_t_has_padding)
// salsa208_word_specification implements the Salsa20/8 core function, also
// described in RFC 7914, section 3. It modifies the block at |inout|
// in-place.
static void salsa208_word_specification(block_t *inout) {
block_t x;
OPENSSL_memcpy(&x, inout, sizeof(x));
for (int i = 8; i > 0; i -= 2) {
x.words[4] ^= CRYPTO_rotl_u32(x.words[0] + x.words[12], 7);
x.words[8] ^= CRYPTO_rotl_u32(x.words[4] + x.words[0], 9);
x.words[12] ^= CRYPTO_rotl_u32(x.words[8] + x.words[4], 13);
x.words[0] ^= CRYPTO_rotl_u32(x.words[12] + x.words[8], 18);
x.words[9] ^= CRYPTO_rotl_u32(x.words[5] + x.words[1], 7);
x.words[13] ^= CRYPTO_rotl_u32(x.words[9] + x.words[5], 9);
x.words[1] ^= CRYPTO_rotl_u32(x.words[13] + x.words[9], 13);
x.words[5] ^= CRYPTO_rotl_u32(x.words[1] + x.words[13], 18);
x.words[14] ^= CRYPTO_rotl_u32(x.words[10] + x.words[6], 7);
x.words[2] ^= CRYPTO_rotl_u32(x.words[14] + x.words[10], 9);
x.words[6] ^= CRYPTO_rotl_u32(x.words[2] + x.words[14], 13);
x.words[10] ^= CRYPTO_rotl_u32(x.words[6] + x.words[2], 18);
x.words[3] ^= CRYPTO_rotl_u32(x.words[15] + x.words[11], 7);
x.words[7] ^= CRYPTO_rotl_u32(x.words[3] + x.words[15], 9);
x.words[11] ^= CRYPTO_rotl_u32(x.words[7] + x.words[3], 13);
x.words[15] ^= CRYPTO_rotl_u32(x.words[11] + x.words[7], 18);
x.words[1] ^= CRYPTO_rotl_u32(x.words[0] + x.words[3], 7);
x.words[2] ^= CRYPTO_rotl_u32(x.words[1] + x.words[0], 9);
x.words[3] ^= CRYPTO_rotl_u32(x.words[2] + x.words[1], 13);
x.words[0] ^= CRYPTO_rotl_u32(x.words[3] + x.words[2], 18);
x.words[6] ^= CRYPTO_rotl_u32(x.words[5] + x.words[4], 7);
x.words[7] ^= CRYPTO_rotl_u32(x.words[6] + x.words[5], 9);
x.words[4] ^= CRYPTO_rotl_u32(x.words[7] + x.words[6], 13);
x.words[5] ^= CRYPTO_rotl_u32(x.words[4] + x.words[7], 18);
x.words[11] ^= CRYPTO_rotl_u32(x.words[10] + x.words[9], 7);
x.words[8] ^= CRYPTO_rotl_u32(x.words[11] + x.words[10], 9);
x.words[9] ^= CRYPTO_rotl_u32(x.words[8] + x.words[11], 13);
x.words[10] ^= CRYPTO_rotl_u32(x.words[9] + x.words[8], 18);
x.words[12] ^= CRYPTO_rotl_u32(x.words[15] + x.words[14], 7);
x.words[13] ^= CRYPTO_rotl_u32(x.words[12] + x.words[15], 9);
x.words[14] ^= CRYPTO_rotl_u32(x.words[13] + x.words[12], 13);
x.words[15] ^= CRYPTO_rotl_u32(x.words[14] + x.words[13], 18);
}
for (int i = 0; i < 16; ++i) {
inout->words[i] += x.words[i];
}
}
// xor_block sets |*out| to be |*a| XOR |*b|.
static void xor_block(block_t *out, const block_t *a, const block_t *b) {
for (size_t i = 0; i < 16; i++) {
out->words[i] = a->words[i] ^ b->words[i];
}
}
// scryptBlockMix implements the function described in RFC 7914, section 4. B'
// is written to |out|. |out| and |B| may not alias and must be each one scrypt
// block (2 * |r| Salsa20 blocks) long.
static void scryptBlockMix(block_t *out, const block_t *B, uint64_t r) {
assert(out != B);
block_t X;
OPENSSL_memcpy(&X, &B[r * 2 - 1], sizeof(X));
for (uint64_t i = 0; i < r * 2; i++) {
xor_block(&X, &X, &B[i]);
salsa208_word_specification(&X);
// This implements the permutation in step 3.
OPENSSL_memcpy(&out[i / 2 + (i & 1) * r], &X, sizeof(X));
}
}
// scryptROMix implements the function described in RFC 7914, section 5. |B| is
// an scrypt block (2 * |r| Salsa20 blocks) and is modified in-place. |T| and
// |V| are scratch space allocated by the caller. |T| must have space for one
// scrypt block (2 * |r| Salsa20 blocks). |V| must have space for |N| scrypt
// blocks (2 * |r| * |N| Salsa20 blocks).
static void scryptROMix(block_t *B, uint64_t r, uint64_t N, block_t *T,
block_t *V) {
// Steps 1 and 2.
#ifdef OPENSSL_BIG_ENDIAN
for(size_t i = 0; i < (2 * r * SCRYPT_BLOCK_WORD_CNT); i++) {
CRYPTO_store_u32_le(&V->words[i], B->words[i]);
}
#else
OPENSSL_memcpy(V, B, 2 * r * sizeof(block_t));
#endif
for (uint64_t i = 1; i < N; i++) {
scryptBlockMix(&V[2 * r * i /* scrypt block i */],
&V[2 * r * (i - 1) /* scrypt block i-1 */], r);
}
scryptBlockMix(B, &V[2 * r * (N - 1) /* scrypt block N-1 */], r);
// Step 3.
for (uint64_t i = 0; i < N; i++) {
// Note this assumes |N| <= 2^32 and is a power of 2.
uint32_t j = B[2 * r - 1].words[0] & (N - 1);
for (size_t k = 0; k < 2 * r; k++) {
xor_block(&T[k], &B[k], &V[2 * r * j + k]);
}
scryptBlockMix(B, T, r);
}
#ifdef OPENSSL_BIG_ENDIAN
for(size_t i = 0; i < (2 * r * SCRYPT_BLOCK_WORD_CNT); i++) {
CRYPTO_store_u32_le(&B->words[i], B->words[i]);
}
#endif
}
// SCRYPT_PR_MAX is the maximum value of p * r. This is equivalent to the
// bounds on p in section 6:
//
// p <= ((2^32-1) * hLen) / MFLen iff
// p <= ((2^32-1) * 32) / (128 * r) iff
// p * r <= (2^30-1)
#define SCRYPT_PR_MAX ((1 << 30) - 1)
// SCRYPT_MAX_MEM is the default maximum memory that may be allocated by
// |EVP_PBE_scrypt|.
#define SCRYPT_MAX_MEM (1024 * 1024 * 32)
int EVP_PBE_scrypt(const char *password, size_t password_len,
const uint8_t *salt, size_t salt_len, uint64_t N, uint64_t r,
uint64_t p, size_t max_mem, uint8_t *out_key,
size_t key_len) {
if (r == 0 || p == 0 || p > SCRYPT_PR_MAX / r ||
// |N| must be a power of two.
N < 2 || (N & (N - 1)) ||
// We only support |N| <= 2^32 in |scryptROMix|.
N > UINT64_C(1) << 32 ||
// Check that |N| < 2^(128×r / 8).
(16 * r <= 63 && N >= UINT64_C(1) << (16 * r))) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PARAMETERS);
return 0;
}
// Determine the amount of memory needed. B, T, and V are |p|, 1, and |N|
// scrypt blocks, respectively. Each scrypt block is 2*|r| |block_t|s.
if (max_mem == 0) {
max_mem = SCRYPT_MAX_MEM;
}
size_t max_scrypt_blocks = max_mem / (2 * r * sizeof(block_t));
if (max_scrypt_blocks < p + 1 ||
max_scrypt_blocks - p - 1 < N) {
OPENSSL_PUT_ERROR(EVP, EVP_R_MEMORY_LIMIT_EXCEEDED);
return 0;
}
// Allocate and divide up the scratch space. |max_mem| fits in a size_t, which
// is no bigger than uint64_t, so none of these operations may overflow.
OPENSSL_STATIC_ASSERT(UINT64_MAX >= SIZE_MAX, size_t_exceeds_uint64_t)
size_t B_blocks = p * 2 * r;
size_t B_bytes = B_blocks * sizeof(block_t);
size_t T_blocks = 2 * r;
size_t V_blocks = N * 2 * r;
block_t *B = OPENSSL_calloc((B_blocks + T_blocks + V_blocks), sizeof(block_t));
if (B == NULL) {
return 0;
}
int ret = 0;
block_t *T = B + B_blocks;
block_t *V = T + T_blocks;
// NOTE: PKCS5_PBKDF2_HMAC can only fail due to allocation failure
// or |iterations| of 0 (we pass 1 here). This is consistent with
// the documented failure conditions of EVP_PBE_scrypt.
if (!PKCS5_PBKDF2_HMAC(password, password_len, salt, salt_len, 1,
EVP_sha256(), B_bytes, (uint8_t *)B)) {
goto err;
}
for (uint64_t i = 0; i < p; i++) {
scryptROMix(B + 2 * r * i, r, N, T, V);
}
if (!PKCS5_PBKDF2_HMAC(password, password_len, (const uint8_t *)B, B_bytes, 1,
EVP_sha256(), key_len, out_key)) {
goto err;
}
ret = 1;
err:
OPENSSL_free(B);
return ret;
}

View File

@@ -0,0 +1,91 @@
// Copyright (c) 2017, Google Inc.
// SPDX-License-Identifier: ISC
#include <stdlib.h>
#include <string.h>
#include <vector>
#include <gtest/gtest.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include "../test/file_test.h"
#include "../test/test_util.h"
static bool GetUint64(FileTest *t, uint64_t *out, const char *name) {
std::string str;
if (!t->GetAttribute(&str, name)) {
return false;
}
char *endptr;
*out = strtoull(str.data(), &endptr, 10);
return !str.empty() && *endptr == '\0';
}
TEST(ScryptTest, TestVectors) {
FileTestGTest("crypto/evp_extra/scrypt_tests.txt", [](FileTest *t) {
std::vector<uint8_t> password, salt, key;
uint64_t N, r, p, max_mem = 0;
ASSERT_TRUE(t->GetBytes(&password, "Password"));
ASSERT_TRUE(t->GetBytes(&salt, "Salt"));
ASSERT_TRUE(t->GetBytes(&key, "Key"));
ASSERT_TRUE(GetUint64(t, &N, "N"));
ASSERT_TRUE(GetUint64(t, &r, "r"));
ASSERT_TRUE(GetUint64(t, &p, "p"));
if (t->HasAttribute("MaxMemory")) {
ASSERT_TRUE(GetUint64(t, &max_mem, "MaxMemory"));
}
std::vector<uint8_t> result(key.size());
ASSERT_TRUE(EVP_PBE_scrypt(reinterpret_cast<const char *>(password.data()),
password.size(), salt.data(), salt.size(), N, r,
p, max_mem, result.data(), result.size()));
EXPECT_EQ(Bytes(key), Bytes(result));
});
}
TEST(ScryptTest, MemoryLimit) {
static const char kPassword[] = "pleaseletmein";
static const char kSalt[] = "SodiumChloride";
// This test requires more than 1GB to run.
uint8_t key[64];
EXPECT_FALSE(EVP_PBE_scrypt(kPassword, strlen(kPassword),
reinterpret_cast<const uint8_t *>(kSalt),
strlen(kSalt), 1048576 /* N */, 8 /* r */,
1 /* p */, 0 /* max_mem */, key, sizeof(key)));
EXPECT_TRUE(
ErrorEquals(ERR_get_error(), ERR_LIB_EVP, EVP_R_MEMORY_LIMIT_EXCEEDED));
}
TEST(ScryptTest, InvalidParameters) {
uint8_t key[64];
// p and r are non-zero.
EXPECT_FALSE(EVP_PBE_scrypt(nullptr, 0, nullptr, 0, 1024 /* N */, 0 /* r */,
1 /* p */, 0 /* max_mem */, key, sizeof(key)));
EXPECT_FALSE(EVP_PBE_scrypt(nullptr, 0, nullptr, 0, 1024 /* N */, 8 /* r */,
0 /* p */, 0 /* max_mem */, key, sizeof(key)));
// N must be a power of 2 > 1.
EXPECT_FALSE(EVP_PBE_scrypt(nullptr, 0, nullptr, 0, 0 /* N */, 8 /* r */,
1 /* p */, 0 /* max_mem */, key, sizeof(key)));
EXPECT_FALSE(EVP_PBE_scrypt(nullptr, 0, nullptr, 0, 1 /* N */, 8 /* r */,
1 /* p */, 0 /* max_mem */, key, sizeof(key)));
EXPECT_FALSE(EVP_PBE_scrypt(nullptr, 0, nullptr, 0, 1023 /* N */, 8 /* r */,
1 /* p */, 0 /* max_mem */, key, sizeof(key)));
EXPECT_TRUE(EVP_PBE_scrypt(nullptr, 0, nullptr, 0, 1024 /* N */, 8 /* r */,
1 /* p */, 0 /* max_mem */, key, sizeof(key)));
EXPECT_FALSE(EVP_PBE_scrypt(nullptr, 0, nullptr, 0, 1025 /* N */, 8 /* r */,
1 /* p */, 0 /* max_mem */, key, sizeof(key)));
// N must be below 2^(128 * r / 8).
EXPECT_FALSE(EVP_PBE_scrypt(nullptr, 0, nullptr, 0, 65536 /* N */, 1 /* r */,
1 /* p */, 0 /* max_mem */, key, sizeof(key)));
EXPECT_TRUE(EVP_PBE_scrypt(nullptr, 0, nullptr, 0, 32768 /* N */, 1 /* r */,
1 /* p */, 0 /* max_mem */, key, sizeof(key)));
}

View File

@@ -0,0 +1,102 @@
// Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) All rights reserved.
// SPDX-License-Identifier: Apache-2.0
#include <openssl/evp.h>
#include <limits.h>
#include <openssl/digest.h>
#include <openssl/err.h>
#include "../fipsmodule/evp/internal.h"
int EVP_SignInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl) {
return EVP_DigestInit_ex(ctx, type, impl);
}
int EVP_SignInit(EVP_MD_CTX *ctx, const EVP_MD *type) {
return EVP_DigestInit(ctx, type);
}
int EVP_SignUpdate(EVP_MD_CTX *ctx, const void *data, size_t len) {
return EVP_DigestUpdate(ctx, data, len);
}
int EVP_SignFinal(const EVP_MD_CTX *ctx, uint8_t *sig, unsigned *out_sig_len,
EVP_PKEY *pkey) {
uint8_t m[EVP_MAX_MD_SIZE];
unsigned m_len;
int ret = 0;
EVP_MD_CTX tmp_ctx;
EVP_PKEY_CTX *pkctx = NULL;
size_t sig_len = EVP_PKEY_size(pkey);
// Ensure the final result will fit in |unsigned|.
if (sig_len > UINT_MAX) {
sig_len = UINT_MAX;
}
*out_sig_len = 0;
EVP_MD_CTX_init(&tmp_ctx);
if (!EVP_MD_CTX_copy_ex(&tmp_ctx, ctx) ||
!EVP_DigestFinal_ex(&tmp_ctx, m, &m_len)) {
goto out;
}
EVP_MD_CTX_cleanup(&tmp_ctx);
pkctx = EVP_PKEY_CTX_new(pkey, NULL);
if (!pkctx || //
!EVP_PKEY_sign_init(pkctx) ||
!EVP_PKEY_CTX_set_signature_md(pkctx, ctx->digest) ||
!EVP_PKEY_sign(pkctx, sig, &sig_len, m, m_len)) {
goto out;
}
*out_sig_len = (unsigned)sig_len;
ret = 1;
out:
EVP_PKEY_CTX_free(pkctx);
return ret;
}
int EVP_VerifyInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl) {
return EVP_DigestInit_ex(ctx, type, impl);
}
int EVP_VerifyInit(EVP_MD_CTX *ctx, const EVP_MD *type) {
return EVP_DigestInit(ctx, type);
}
int EVP_VerifyUpdate(EVP_MD_CTX *ctx, const void *data, size_t len) {
return EVP_DigestUpdate(ctx, data, len);
}
int EVP_VerifyFinal(EVP_MD_CTX *ctx, const uint8_t *sig, size_t sig_len,
EVP_PKEY *pkey) {
uint8_t m[EVP_MAX_MD_SIZE];
unsigned m_len;
int ret = 0;
EVP_MD_CTX tmp_ctx;
EVP_PKEY_CTX *pkctx = NULL;
EVP_MD_CTX_init(&tmp_ctx);
if (!EVP_MD_CTX_copy_ex(&tmp_ctx, ctx) ||
!EVP_DigestFinal_ex(&tmp_ctx, m, &m_len)) {
EVP_MD_CTX_cleanup(&tmp_ctx);
goto out;
}
EVP_MD_CTX_cleanup(&tmp_ctx);
pkctx = EVP_PKEY_CTX_new(pkey, NULL);
if (!pkctx ||
!EVP_PKEY_verify_init(pkctx) ||
!EVP_PKEY_CTX_set_signature_md(pkctx, ctx->digest)) {
goto out;
}
ret = EVP_PKEY_verify(pkctx, sig, sig_len, m, m_len);
out:
EVP_PKEY_CTX_free(pkctx);
return ret;
}