int aws_cryptosdk_sig_sign_start()

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;
}