diff options
author | Richard Levitte <levitte@openssl.org> | 2020-03-31 16:54:43 +0200 |
---|---|---|
committer | Richard Levitte <levitte@openssl.org> | 2020-04-07 11:16:56 +0200 |
commit | 1d39620b3489d957978ef038be4533300d7c4179 (patch) | |
tree | 85cc10b7ac0a12e9dae84ff52fd22d566baf7d26 /crypto | |
parent | 77de6bb38d3bc247eac548715969b01cc2b752bb (diff) |
PROV: Add the beginning of a DER writing library
This library is meant to be small and quick. It's based on WPACKET,
which was extended to support DER writing. The way it's used is a
bit unusual, as it's used to write the structures backward into a
given buffer. A typical quick call looks like this:
/*
* Fill in this structure:
*
* something ::= SEQUENCE {
* id OBJECT IDENTIFIER,
* x [0] INTEGER OPTIONAL,
* y [1] BOOLEAN OPTIONAL,
* n INTEGER
* }
*/
unsigned char buf[nnnn], *p = NULL;
size_t encoded_len = 0;
WPACKET pkt;
int ok;
ok = WPACKET_init_der(&pkt, buf, sizeof(buf)
&& DER_w_start_sequence(&pkt, -1)
&& DER_w_bn(&pkt, -1, bn)
&& DER_w_boolean(&pkt, 1, bool)
&& DER_w_precompiled(&pkt, -1, OID, sizeof(OID))
&& DER_w_end_sequence(&pkt, -1)
&& WPACKET_finish(&pkt)
&& WPACKET_get_total_written(&pkt, &encoded_len)
&& (p = WPACKET_get_curr(&pkt)) != NULL;
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/11450)
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/build.info | 2 | ||||
-rw-r--r-- | crypto/der_writer.c | 142 |
2 files changed, 143 insertions, 1 deletions
diff --git a/crypto/build.info b/crypto/build.info index baa31ee8e1..864506a18d 100644 --- a/crypto/build.info +++ b/crypto/build.info @@ -71,7 +71,7 @@ $UTIL_COMMON=\ cryptlib.c params.c params_from_text.c bsearch.c ex_data.c o_str.c \ ctype.c threads_pthread.c threads_win.c threads_none.c initthread.c \ context.c sparse_array.c asn1_dsa.c packet.c param_build.c $CPUIDASM \ - param_build_set.c + param_build_set.c der_writer.c $UTIL_DEFINE=$CPUIDDEF SOURCE[../libcrypto]=$UTIL_COMMON \ diff --git a/crypto/der_writer.c b/crypto/der_writer.c new file mode 100644 index 0000000000..26fd88592d --- /dev/null +++ b/crypto/der_writer.c @@ -0,0 +1,142 @@ +/* + * Copyright 2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <stdlib.h> +#include <string.h> +#include "internal/cryptlib.h" +#include "internal/der.h" +#include "crypto/bn.h" + +static int int_start_context(WPACKET *pkt, int tag) +{ + if (tag < 0) + return 1; + if (!ossl_assert(tag <= 30)) + return 0; + return WPACKET_start_sub_packet(pkt); +} + +static int int_end_context(WPACKET *pkt, int tag) +{ + if (tag < 0) + return 1; + if (!ossl_assert(tag <= 30)) + return 0; + return WPACKET_close(pkt) + && WPACKET_put_bytes_u8(pkt, DER_C_CONTEXT | tag); +} + +int DER_w_precompiled(WPACKET *pkt, int tag, + const unsigned char *precompiled, size_t precompiled_n) +{ + return int_start_context(pkt, tag) + && WPACKET_memcpy(pkt, precompiled, precompiled_n) + && int_end_context(pkt, tag); +} + +int DER_w_boolean(WPACKET *pkt, int tag, int b) +{ + return int_start_context(pkt, tag) + && WPACKET_start_sub_packet(pkt) + && (!b || WPACKET_put_bytes_u8(pkt, 0xFF)) + && !WPACKET_close(pkt) + && !WPACKET_put_bytes_u8(pkt, DER_P_BOOLEAN) + && int_end_context(pkt, tag); +} + +static int int_der_w_integer(WPACKET *pkt, int tag, + int (*put_bytes)(WPACKET *pkt, const void *v, + unsigned int *top_byte), + const void *v) +{ + unsigned int top_byte = 0; + + return int_start_context(pkt, tag) + && WPACKET_start_sub_packet(pkt) + && put_bytes(pkt, v, &top_byte) + && ((top_byte & 0x80) == 0 || WPACKET_put_bytes_u8(pkt, 0)) + && WPACKET_close(pkt) + && WPACKET_put_bytes_u8(pkt, DER_P_INTEGER) + && int_end_context(pkt, tag); +} + +static int int_put_bytes_ulong(WPACKET *pkt, const void *v, + unsigned int *top_byte) +{ + const unsigned long *value = v; + unsigned long tmp = *value; + size_t n = 0; + + while (tmp != 0) { + n++; + *top_byte = (tmp & 0xFF); + tmp >>= 8; + } + if (n == 0) + n = 1; + + return WPACKET_put_bytes__(pkt, *value, n); +} + +/* For integers, we only support unsigned values for now */ +int DER_w_ulong(WPACKET *pkt, int tag, unsigned long v) +{ + return int_der_w_integer(pkt, tag, int_put_bytes_ulong, &v); +} + +static int int_put_bytes_bn(WPACKET *pkt, const void *v, + unsigned int *top_byte) +{ + unsigned char *p = NULL; + size_t n = BN_num_bytes(v); + + /* The BIGNUM limbs are in LE order */ + *top_byte = + ((bn_get_words(v) [(n - 1) / BN_BYTES]) >> (8 * ((n - 1) % BN_BYTES))) + & 0xFF; + + if (!WPACKET_allocate_bytes(pkt, n, &p)) + return 0; + if (p != NULL) + BN_bn2bin(v, p); + return 1; +} + +int DER_w_bn(WPACKET *pkt, int tag, const BIGNUM *v) +{ + if (v == NULL || BN_is_negative(v)) + return 0; + if (BN_is_zero(v)) + return DER_w_ulong(pkt, tag, 0); + + return int_der_w_integer(pkt, tag, int_put_bytes_bn, v); +} + +int DER_w_null(WPACKET *pkt, int tag) +{ + return int_start_context(pkt, tag) + && WPACKET_start_sub_packet(pkt) + && WPACKET_close(pkt) + && WPACKET_put_bytes_u8(pkt, DER_P_NULL) + && int_end_context(pkt, tag); +} + +/* Constructed things need a start and an end */ +int DER_w_begin_sequence(WPACKET *pkt, int tag) +{ + return int_start_context(pkt, tag) + && WPACKET_start_sub_packet(pkt); +} + +int DER_w_end_sequence(WPACKET *pkt, int tag) +{ + return WPACKET_close(pkt) + && WPACKET_put_bytes_u8(pkt, DER_F_CONSTRUCTED | DER_P_SEQUENCE) + && int_end_context(pkt, tag); +} |