in source/cipher_openssl.c [540:681]
int aws_cryptosdk_sig_sign_start(
struct aws_cryptosdk_sig_ctx **ctx,
struct aws_allocator *alloc,
struct aws_string **pub_key_str,
const struct aws_cryptosdk_alg_properties *props,
const struct aws_string *priv_key) {
AWS_PRECONDITION(AWS_OBJECT_PTR_IS_WRITABLE(ctx));
AWS_PRECONDITION(AWS_OBJECT_PTR_IS_READABLE(alloc));
AWS_PRECONDITION(AWS_OBJECT_PTR_IS_READABLE(props));
AWS_PRECONDITION(aws_cryptosdk_alg_properties_is_valid(props));
AWS_PRECONDITION(aws_string_is_valid(priv_key));
/* See comments in aws_cryptosdk_sig_get_privkey re the serialized format */
*ctx = NULL;
if (pub_key_str) {
*pub_key_str = NULL;
}
if (!props->impl->curve_name) {
AWS_POSTCONDITION(!*ctx);
AWS_POSTCONDITION(!pub_key_str || !*pub_key_str);
AWS_POSTCONDITION(aws_string_is_valid(priv_key));
return AWS_OP_SUCCESS;
}
if (priv_key->len < 5) {
// We don't have room for the algorithm ID plus the serialized private key.
// Someone has apparently handed us a truncated private key?
AWS_POSTCONDITION(!*ctx);
AWS_POSTCONDITION(!pub_key_str || !*pub_key_str);
AWS_POSTCONDITION(aws_string_is_valid(priv_key));
return aws_raise_error(AWS_CRYPTOSDK_ERR_CRYPTO_UNKNOWN);
}
EC_KEY *keypair = NULL;
EC_GROUP *group = NULL;
ASN1_INTEGER *priv_key_asn1 = NULL;
BIGNUM *priv_key_bn = NULL;
struct aws_byte_cursor cursor = aws_byte_cursor_from_string(priv_key);
struct aws_byte_cursor field;
uint16_t serialized_alg_id;
uint8_t privkey_len, pubkey_len;
const uint8_t *bufp;
int rv;
if (!aws_byte_cursor_read_be16(&cursor, &serialized_alg_id) || !aws_byte_cursor_read_u8(&cursor, &pubkey_len) ||
!aws_byte_cursor_read_u8(&cursor, &privkey_len)) {
aws_raise_error(AWS_CRYPTOSDK_ERR_CRYPTO_UNKNOWN);
goto out;
}
if (serialized_alg_id != props->alg_id) {
// Algorithm mismatch
AWS_POSTCONDITION(!*ctx);
AWS_POSTCONDITION(!pub_key_str || !*pub_key_str);
AWS_POSTCONDITION(aws_string_is_valid(priv_key));
return aws_raise_error(AWS_CRYPTOSDK_ERR_CRYPTO_UNKNOWN);
}
if (!(keypair = EC_KEY_new())) {
aws_raise_error(AWS_ERROR_OOM);
goto out;
}
if (!(group = group_for_props(props))) {
aws_raise_error(AWS_CRYPTOSDK_ERR_CRYPTO_UNKNOWN);
goto out;
}
if (!EC_KEY_set_group(keypair, group)) {
aws_raise_error(AWS_CRYPTOSDK_ERR_CRYPTO_UNKNOWN);
EC_GROUP_free(group);
goto out;
}
EC_GROUP_free(group);
EC_KEY_set_conv_form(keypair, POINT_CONVERSION_COMPRESSED);
field = aws_byte_cursor_advance(&cursor, pubkey_len);
bufp = field.ptr;
if (!field.ptr || !o2i_ECPublicKey(&keypair, &bufp, field.len) || bufp != field.ptr + field.len) {
ERR_print_errors_fp(stderr);
aws_raise_error(AWS_CRYPTOSDK_ERR_CRYPTO_UNKNOWN);
goto out;
}
field = aws_byte_cursor_advance(&cursor, privkey_len);
bufp = field.ptr;
if (!field.ptr || !d2i_ASN1_INTEGER(&priv_key_asn1, &bufp, field.len) || bufp != field.ptr + field.len) {
ASN1_STRING_clear_free(priv_key_asn1);
aws_raise_error(AWS_CRYPTOSDK_ERR_CRYPTO_UNKNOWN);
goto out;
}
priv_key_bn = ASN1_INTEGER_to_BN(priv_key_asn1, NULL);
// ASN1_INTEGERS are really ASN1_STRINGS; since there's no ASN1_INTEGER_clear_free, we'll use
// ASN1_STRING_clear_free instead.
ASN1_STRING_clear_free(priv_key_asn1);
if (!priv_key_bn) {
aws_raise_error(AWS_ERROR_OOM);
goto out;
}
rv = EC_KEY_set_private_key(keypair, priv_key_bn);
BN_clear_free(priv_key_bn);
if (!rv) {
aws_raise_error(AWS_ERROR_OOM);
goto out;
}
if (cursor.len) {
// Trailing garbage in the serialized private key
// This should never happen, as this is an internal (trusted) datapath, but
// check anyway
aws_raise_error(AWS_CRYPTOSDK_ERR_CRYPTO_UNKNOWN);
goto out;
}
if (pub_key_str && serialize_pubkey(alloc, keypair, pub_key_str)) {
EC_KEY_free(keypair);
AWS_POSTCONDITION(!*ctx);
AWS_POSTCONDITION(!*pub_key_str);
AWS_POSTCONDITION(aws_string_is_valid(priv_key));
return AWS_OP_ERR;
}
*ctx = sign_start(alloc, keypair, props);
if (!*ctx && pub_key_str) {
aws_string_destroy(*pub_key_str);
*pub_key_str = NULL;
}
out:
// EC_KEYs are reference counted
EC_KEY_free(keypair);
AWS_POSTCONDITION(!*ctx || (aws_cryptosdk_sig_ctx_is_valid(*ctx) && (*ctx)->is_sign));
AWS_POSTCONDITION(!pub_key_str || (!*ctx && !*pub_key_str) || aws_string_is_valid(*pub_key_str));
AWS_POSTCONDITION(aws_string_is_valid(priv_key));
return *ctx ? AWS_OP_SUCCESS : AWS_OP_ERR;
}