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 /doc/internal | |
parent | 77de6bb38d3bc247eac548715969b01cc2b752bb (diff) | |
download | openssl-1d39620b3489d957978ef038be4533300d7c4179.tar.gz |
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 'doc/internal')
-rw-r--r-- | doc/internal/man3/DER_w_begin_sequence.pod | 48 | ||||
-rw-r--r-- | doc/internal/man3/DER_w_bn.pod | 56 | ||||
-rw-r--r-- | doc/internal/man3/DER_w_precompiled.pod | 48 | ||||
-rw-r--r-- | doc/internal/man7/DERlib.pod | 148 |
4 files changed, 300 insertions, 0 deletions
diff --git a/doc/internal/man3/DER_w_begin_sequence.pod b/doc/internal/man3/DER_w_begin_sequence.pod new file mode 100644 index 0000000000..3d221a942f --- /dev/null +++ b/doc/internal/man3/DER_w_begin_sequence.pod @@ -0,0 +1,48 @@ +=pod + +=head1 NAME + +DER_w_begin_sequence, DER_w_end_sequence +- internal DER writers for DER constructed elements + +=head1 SYNOPSIS + + #include "internal/der.h" + + int DER_w_begin_sequence(WPACKET *pkt, int tag); + int DER_w_end_sequence(WPACKET *pkt, int tag); + +=head1 DESCRIPTION + +All functions described here are wrappers for constructed structures, +i.e. the ASN.1 SEQUENCE, SET and CHOICE specifications. They all come +in pairs, as noted by the function names containing the words C<begin> +and B<end>. + +When using these, special care must be taken to ensure that the ASN.1 tag +value I<tag> is the same in the matching C<begin> and C<end> function calls. + +DER_w_begin_sequence() and DER_w_end_sequence() begins and ends a +SEQUENCE. + +=head1 RETURN VALUES + +All the functions return 1 on success and 0 on failure. Failure may +mean that the buffer held by the I<pkt> is too small, but may also +mean that the values given to the functions are invalid, such as the provided +I<tag> value being too large for the implementation. + +=head1 SEE ALSO + +L<DERlib(7)> + +=head1 COPYRIGHT + +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 +L<https://www.openssl.org/source/license.html>. + +=cut diff --git a/doc/internal/man3/DER_w_bn.pod b/doc/internal/man3/DER_w_bn.pod new file mode 100644 index 0000000000..c51223f71a --- /dev/null +++ b/doc/internal/man3/DER_w_bn.pod @@ -0,0 +1,56 @@ +=pod + +=head1 NAME + +DER_w_boolean, DER_w_ulong, DER_w_bn, DER_w_null +- internal DER writers for DER primitives + +=head1 SYNOPSIS + + #include "internal/der.h" + + int DER_w_boolean(WPACKET *pkt, int tag, int b); + int DER_w_ulong(WPACKET *pkt, int tag, unsigned long v); + int DER_w_bn(WPACKET *pkt, int tag, const BIGNUM *v); + int DER_w_null(WPACKET *pkt, int tag); + +=head1 DESCRIPTION + +All functions described here behave the same way, they prepend +(remember that DER writers are used backwards) the DER encoding of +their respective value to the already written output buffer held by +I<pkt>. + +DER_w_boolean() writes the primitive BOOLEAN using the value I<b>. +Any value that evaluates as true will render a B<true> BOOLEAN, +otherwise a B<false> BOOLEAN. + +DER_w_ulong() and DER_w_bn() both write the primitive INTEGER using +the value I<v>. + +=for comment Other similar functions for diverse C integers should be +added. + +DER_w_null() writes the primitive NULL. + +=head1 RETURN VALUES + +All the functions return 1 on success and 0 on failure. Failure may +mean that the buffer held by the I<pkt> is too small, but may also +mean that the values given to the functions are invalid, such as the provided +I<tag> value being too large for the implementation. + +=head1 SEE ALSO + +L<DERlib(7)> + +=head1 COPYRIGHT + +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 +L<https://www.openssl.org/source/license.html>. + +=cut diff --git a/doc/internal/man3/DER_w_precompiled.pod b/doc/internal/man3/DER_w_precompiled.pod new file mode 100644 index 0000000000..81a92526af --- /dev/null +++ b/doc/internal/man3/DER_w_precompiled.pod @@ -0,0 +1,48 @@ +=pod + +=head1 NAME + +DER_w_precompiled +- internal DER writers for precompiled DER blobs + +=head1 SYNOPSIS + + #include "internal/der.h" + + int DER_w_precompiled(WPACKET *pkt, int tag, + const unsigned char *precompiled, + size_t precompiled_n); + +=head1 DESCRIPTION + +There may be already existing DER blobs that can simply be copied to +the buffer held by I<pkt>. For example, precompiled values, such as +OIDs (for example, C<id-sha256>) or complete AlgorithmIdentifiers +(for example, C<sha256Identifier>). To add those as an element in a +structure being DER encoded, use DER_w_precompiled(). + +DER_w_precompiled() will simply take the DER encoded blob given as +I<precompiled> with length I<precompiled_n> and add it to the buffer +held by I<pkt>. + +=head1 RETURN VALUES + +DER_w_precompiled() returns 1 on success and 0 on failure. Failure +may mean that the buffer held by the I<pkt> is too small, but may also +mean that the values given to the functions are invalid, such as the provided +I<tag> value being too large for the implementation. + +=head1 SEE ALSO + +L<DERlib(7)> + +=head1 COPYRIGHT + +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 +L<https://www.openssl.org/source/license.html>. + +=cut diff --git a/doc/internal/man7/DERlib.pod b/doc/internal/man7/DERlib.pod new file mode 100644 index 0000000000..7b0e7225f0 --- /dev/null +++ b/doc/internal/man7/DERlib.pod @@ -0,0 +1,148 @@ +=pod + +=head1 NAME + +DERlib - internal OpenSSL DER library + +=head1 DESCRIPTION + +OpenSSL contains an internal small DER reading and writing library, +as an alternative to the publically known i2d and d2i functions. It's +solely constituted of functions that work as building blocks to create +more similar functions to encode and decode larger structures. + +All these functions have similar function signatures (C<something> +will vary depending on what the function will encode): + + int DER_w_something(WPACKET *pkt, int tag, ...); + +=begin comment + +When readers are added, add this: + + int DER_r_something(PACKET *pkt, int tag, ...); + +=end comment + +I<pkt> is the packet context used, and I<tag> should be the +context-specific tag value of the element being handled, or -1 if there +is no tag number for that element (you may use the convenience macro +B<DER_NO_CONTEXT> instead of -1). Any argument following is the C +variable that's being encoded or decoded. + +=head2 DER writers / encoders + +DER writers are based in L<WPACKET(3)>, a generic packet writing +library, so before using any of them, I<pkt> must be initialized +using L<WPACKET_init_der(3)> or L<WPACKET_init_null_der(3)> + +DER writers must be used in reverse order, except for the wrapping +functions that implement a constructed element. The latter are easily +recognised by their function name including the words C<begin> and +C<end>. As an example, we can look at the DSA signature structure, +which is defined like this in ASN.1 terms: + + -- Copied from RFC 3279, section 2.2.2 + Dss-Sig-Value ::= SEQUENCE { + r INTEGER, + s INTEGER } + +With the DER library, this is the correspoding code, given two OpenSSL +B<BIGNUM>s I<r> and I<s>: + + int ok = DER_w_begin_sequence(pkt, -1) + && DER_w_bn(pkg, -1, s) + && DER_w_bn(pkg, -1, r) + && DER_w_end_sequence(pkt, -1); + +As an example of the use of I<tag>, an ASN.1 element like this: + + v [1] INTEGER OPTIONAL + +Would be encoded like this: + + DER_w_bn(pkt, 1, v) + +=begin comment + +=head2 DER readers / decoders + +TBA + +=end comment + +=head1 EXAMPLES + +A more complex example, encoding the AlgorithmIdentifier with +RSASSA-PSS values. + +As a reminder, the AlgorithmIdentifier is specified like this: + + -- From RFC 3280, section 4.1.1.2 + AlgorithmIdentifier ::= SEQUENCE { + algorithm OBJECT IDENTIFIER, + parameters ANY DEFINED BY algorithm OPTIONAL } + +And the RSASSA-PSS OID and parameters are specified like this: + + -- From RFC 3279, section 3.1 + id-RSASSA-PSS OBJECT IDENTIFIER ::= { pkcs-1 10 } + + RSASSA-PSS-params ::= SEQUENCE { + hashAlgorithm [0] HashAlgorithm DEFAULT + sha1Identifier, + maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT + mgf1SHA1Identifier, + saltLength [2] INTEGER DEFAULT 20, + trailerField [3] INTEGER DEFAULT 1 } + +The value we want to encode, written in ASN.1 syntax: + + { + algorithm id-RSASSA-PSS, + parameters { + hashAlgorithm sha256Identifier, + maskGenAlgorithm mgf1SHA256Identifier, + saltLength 20 -- unnecessarily explicit + } + } + +Assuming that we have precompiled constants for C<id-RSASSA-PSS>, +C<sha256Identifier> and C<mgf1SHA256Identifier>, the DER writing code +looks as follows. This is a complete function to write that specific +value: + + int DER_w_AlgorithmIdentifier_RSASSA_PSS_special(WPACKET *pkt, + int tag, + RSA *rsa) + { + return DER_w_begin_sequence(pkt, tag) + && (DER_w_begin_sequence(pkt, DER_NO_CONTEXT) + && DER_w_ulong(pkt, 2, 20) + && DER_w_precompiled(pkt, 1, + der_mgf1SHA256Identifier, + sizeof(der_mgf1SHA256Identifier)) + && DER_w_precompiled(pkt, 0, + der_sha256Identifier, + sizeof(der_sha256Identifier)) + && DER_w_end_sequence(pkt, DER_NO_CONTEXT)) + && DER_w_precompiled(pkt, DER_NO_CONTEXT, + der_id_RSASSA_PSS, + sizeof(der_id_RSASSA_PSS)) + && DER_w_end_sequence(pkt, tag); + } + +=head1 SEE ALSO + +L<DER_w_bn(3)>, L<DER_w_begin_sequence(3)>, L<DER_w_precompiled(3)> + +=head1 COPYRIGHT + +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 +L<https://www.openssl.org/source/license.html>. + +=cut |