static int sign_header()

in source/session_encrypt.c [183:269]


static int sign_header(struct aws_cryptosdk_session *session) {
    AWS_PRECONDITION(aws_cryptosdk_session_is_valid(session));
    AWS_PRECONDITION(aws_cryptosdk_alg_properties_is_valid(session->alg_props));
    AWS_PRECONDITION(session->alg_props->impl->cipher_ctor != NULL);
    AWS_PRECONDITION(session->header.iv.len <= session->alg_props->iv_len);
    AWS_PRECONDITION(session->header.auth_tag.len <= session->alg_props->tag_len);
    AWS_PRECONDITION(session->state == ST_GEN_KEY);
    AWS_PRECONDITION(session->mode == AWS_CRYPTOSDK_ENCRYPT);
    session->header_size = aws_cryptosdk_hdr_size(&session->header);

    if (session->header_size == 0) {
        // EDK field lengths resulted in size_t overflow
        return aws_raise_error(AWS_CRYPTOSDK_ERR_LIMIT_EXCEEDED);
    }

    if (!(session->header_copy = aws_mem_acquire(session->alloc, session->header_size))) {
        return aws_raise_error(AWS_ERROR_OOM);
    }

    // Debug memsets - if something goes wrong below this makes it easier to
    // see what happened. It also makes sure that the header is fully initialized,
    // again just in case some bug doesn't overwrite them properly.

    if (session->header.iv.len != 0) {
        assert(session->header.iv.buffer);
        memset(session->header.iv.buffer, 0x42, session->header.iv.len);
    }
    if (session->header.auth_tag.len != 0) {
        assert(session->header.auth_tag.buffer);
        memset(session->header.auth_tag.buffer, 0xDE, session->header.auth_tag.len);
    }

    size_t actual_size;

    int rv = aws_cryptosdk_hdr_write(&session->header, &actual_size, session->header_copy, session->header_size);

    if (rv) return AWS_OP_ERR;
    if (actual_size != session->header_size) {
        return aws_raise_error(AWS_CRYPTOSDK_ERR_CRYPTO_UNKNOWN);
    }

    size_t authtag_len = aws_cryptosdk_private_authtag_len(session->alg_props);

    struct aws_byte_buf to_sign = aws_byte_buf_from_array(session->header_copy, session->header_size - authtag_len);
    struct aws_byte_buf authtag =
        aws_byte_buf_from_array(session->header_copy + session->header_size - authtag_len, authtag_len);

    rv = aws_cryptosdk_sign_header(session->alg_props, &session->content_key, &authtag, &to_sign);
    if (rv) return AWS_OP_ERR;

    if (session->alg_props->msg_format_version == AWS_CRYPTOSDK_HEADER_VERSION_1_0) {
        if (session->header.iv.len != 0) {
            assert(session->header.iv.buffer);
            memcpy(session->header.iv.buffer, authtag.buffer, session->header.iv.len);
        }
        if (session->header.auth_tag.len != 0) {
            assert(session->header.auth_tag.buffer);
            memcpy(
                session->header.auth_tag.buffer, authtag.buffer + session->header.iv.len, session->header.auth_tag.len);
        }
    } else {
        if (session->header.auth_tag.len != 0) {
            assert(session->header.auth_tag.buffer);
            memcpy(session->header.auth_tag.buffer, authtag.buffer, session->header.auth_tag.len);
        }
    }

    // Re-serialize the header now that we know the auth tag
    rv = aws_cryptosdk_hdr_write(&session->header, &actual_size, session->header_copy, session->header_size);
    if (rv) return AWS_OP_ERR;
    if (actual_size != session->header_size) {
        return aws_raise_error(AWS_CRYPTOSDK_ERR_CRYPTO_UNKNOWN);
    }

    if (session->signctx &&
        aws_cryptosdk_sig_update(
            session->signctx, aws_byte_cursor_from_array(session->header_copy, session->header_size))) {
        return AWS_OP_ERR;
    }

    session->frame_seqno = 1;
    aws_cryptosdk_priv_session_change_state(session, ST_WRITE_HEADER);

    // TODO - should we free the parsed header here?

    return AWS_OP_SUCCESS;
}