[openssl] master update
Richard Levitte
levitte at openssl.org
Tue Apr 7 09:21:34 UTC 2020
The branch master has been updated
via 2d956b320c910a90528e9a3aeb4cf48221dba246 (commit)
via 8c555803476a2af366938161d1186a0d746910ea (commit)
via 6f5837dc1621882a3a9f34a2910321751ab002c2 (commit)
via 1d39620b3489d957978ef038be4533300d7c4179 (commit)
via 77de6bb38d3bc247eac548715969b01cc2b752bb (commit)
from 3cb55fe47c3398b81956e4fe20c4004524d47519 (commit)
- Log -----------------------------------------------------------------
commit 2d956b320c910a90528e9a3aeb4cf48221dba246
Author: Richard Levitte <levitte at openssl.org>
Date: Tue Mar 31 17:20:24 2020 +0200
PROV: Add DERlib support for ECDSA and EC keys
This replaces crypto/ec/ecdsa_aid.c with new code and generated OIDs
Reviewed-by: Matt Caswell <matt at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/11450)
commit 8c555803476a2af366938161d1186a0d746910ea
Author: Richard Levitte <levitte at openssl.org>
Date: Tue Mar 31 17:16:59 2020 +0200
PROV: Add DERlib support for DSA
This replaces crypto/dsa/dsa_aid.c with new code and generated OIDs
Reviewed-by: Matt Caswell <matt at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/11450)
commit 6f5837dc1621882a3a9f34a2910321751ab002c2
Author: Richard Levitte <levitte at openssl.org>
Date: Tue Mar 31 17:15:17 2020 +0200
PROV: Add DERlib support for RSA
This replaces crypto/rsa/rsa_aid.c with new code and generated OIDs
Reviewed-by: Matt Caswell <matt at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/11450)
commit 1d39620b3489d957978ef038be4533300d7c4179
Author: Richard Levitte <levitte at openssl.org>
Date: Tue Mar 31 16:54:43 2020 +0200
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 at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/11450)
commit 77de6bb38d3bc247eac548715969b01cc2b752bb
Author: Richard Levitte <levitte at openssl.org>
Date: Tue Mar 31 16:42:04 2020 +0200
Add perl support to parse and DER encode ASN.1 OID specs
We have an old OID database that's not as readable as would be
desired, and we have spots with hand coded DER for well known OIDs.
The perl modules added here give enough support that we can parse
OBJECT IDENTIFIER definitions and encode them as DER.
OpenSSL::OID is a general OID parsing and encoding of ASN.1
definitions, and supports enough of the X.680 syntax to understand
what we find in RFCs and similar documents and produce the DER
encoding for them.
oids_to_c is a specialized module to convert the DER encoding from
OpenSSL::OID to C code. This is primarily useful in file templates
that are processed with util/dofile.pl.
Reviewed-by: Matt Caswell <matt at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/11450)
-----------------------------------------------------------------------
Summary of changes:
crypto/build.info | 2 +-
crypto/der_writer.c | 142 ++++++++++
crypto/dsa/build.info | 2 +-
crypto/dsa/dsa_aid.c | 70 -----
crypto/ec/build.info | 2 +-
crypto/ec/ecdsa_aid.c | 105 -------
crypto/rsa/build.info | 2 +-
crypto/rsa/rsa_aid.c | 98 -------
doc/internal/man3/DER_w_begin_sequence.pod | 48 ++++
doc/internal/man3/DER_w_bn.pod | 56 ++++
doc/internal/man3/DER_w_precompiled.pod | 48 ++++
doc/internal/man7/DERlib.pod | 148 ++++++++++
include/internal/der.h | 84 ++++++
providers/common/build.info | 2 +
providers/common/der/DSA.asn1 | 29 ++
providers/common/der/EC.asn1 | 83 ++++++
providers/common/der/RSA.asn1 | 88 ++++++
providers/common/der/build.info | 25 ++
providers/common/der/der_dsa.c.in | 59 ++++
providers/common/der/der_dsa.h.in | 21 ++
providers/common/der/der_ec.c.in | 67 +++++
providers/common/der/der_ec.h.in | 21 ++
providers/common/der/der_rsa.c.in | 74 +++++
providers/common/der/der_rsa.h.in | 21 ++
providers/common/der/oids_to_c.pm | 111 ++++++++
providers/implementations/signature/build.info | 4 +
providers/implementations/signature/dsa.c | 39 ++-
providers/implementations/signature/ecdsa.c | 31 ++-
providers/implementations/signature/rsa.c | 41 +--
util/missingcrypto.txt | 3 +
util/perl/OpenSSL/OID.pm | 365 +++++++++++++++++++++++++
31 files changed, 1574 insertions(+), 317 deletions(-)
create mode 100644 crypto/der_writer.c
delete mode 100644 crypto/dsa/dsa_aid.c
delete mode 100644 crypto/ec/ecdsa_aid.c
delete mode 100644 crypto/rsa/rsa_aid.c
create mode 100644 doc/internal/man3/DER_w_begin_sequence.pod
create mode 100644 doc/internal/man3/DER_w_bn.pod
create mode 100644 doc/internal/man3/DER_w_precompiled.pod
create mode 100644 doc/internal/man7/DERlib.pod
create mode 100644 include/internal/der.h
create mode 100644 providers/common/der/DSA.asn1
create mode 100644 providers/common/der/EC.asn1
create mode 100644 providers/common/der/RSA.asn1
create mode 100644 providers/common/der/build.info
create mode 100644 providers/common/der/der_dsa.c.in
create mode 100644 providers/common/der/der_dsa.h.in
create mode 100644 providers/common/der/der_ec.c.in
create mode 100644 providers/common/der/der_ec.h.in
create mode 100644 providers/common/der/der_rsa.c.in
create mode 100644 providers/common/der/der_rsa.h.in
create mode 100644 providers/common/der/oids_to_c.pm
create mode 100644 util/perl/OpenSSL/OID.pm
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);
+}
diff --git a/crypto/dsa/build.info b/crypto/dsa/build.info
index d8f035000d..fb5a4fee2a 100644
--- a/crypto/dsa/build.info
+++ b/crypto/dsa/build.info
@@ -1,6 +1,6 @@
LIBS=../../libcrypto
-$COMMON=dsa_sign.c dsa_vrf.c dsa_lib.c dsa_ossl.c dsa_aid.c dsa_check.c \
+$COMMON=dsa_sign.c dsa_vrf.c dsa_lib.c dsa_ossl.c dsa_check.c \
dsa_key.c dsa_backend.c
SOURCE[../../libcrypto]=$COMMON\
diff --git a/crypto/dsa/dsa_aid.c b/crypto/dsa/dsa_aid.c
deleted file mode 100644
index 505e2e2f40..0000000000
--- a/crypto/dsa/dsa_aid.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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 <openssl/objects.h>
-#include "crypto/dsa.h"
-
-#define ASN1_SEQUENCE 0x30
-#define ASN1_OID 0x06
-
-/*
- * id-dsa-with-sha1 OBJECT IDENTIFIER ::= {
- * iso(1) member-body(2) us(840) x9-57(10040) x9cm(4) 3
- * }
- */
-#define ENCODE_ALGORITHMIDENTIFIER_RFC3279(name, n) \
- static const unsigned char algorithmidentifier_##name##_der[] = { \
- ASN1_SEQUENCE, 0x09, \
- ASN1_OID, 0x07, 1 * 40 + 2, 134, 72, 206, 56, 4, n \
-}
-
-ENCODE_ALGORITHMIDENTIFIER_RFC3279(sha1, 3);
-
-/*
- * dsaWithSHAx OIDs are of the form: (sigAlgs |n|)
- * where sigAlgs OBJECT IDENTIFIER ::= { 2 16 840 1 101 3 4 3 }
- */
-#define ENCODE_ALGORITHMIDENTIFIER_SIGALGS(name, n) \
- static const unsigned char algorithmidentifier_##name##_der[] = { \
- ASN1_SEQUENCE, 0x0b, \
- ASN1_OID, 0x09, 2 * 40 + 16, 0x86, 0x48, 1, 101, 3, 4, 3, n \
-}
-
-ENCODE_ALGORITHMIDENTIFIER_SIGALGS(sha224, 1);
-ENCODE_ALGORITHMIDENTIFIER_SIGALGS(sha256, 2);
-ENCODE_ALGORITHMIDENTIFIER_SIGALGS(sha384, 3);
-ENCODE_ALGORITHMIDENTIFIER_SIGALGS(sha512, 4);
-ENCODE_ALGORITHMIDENTIFIER_SIGALGS(sha3_224, 5);
-ENCODE_ALGORITHMIDENTIFIER_SIGALGS(sha3_256, 6);
-ENCODE_ALGORITHMIDENTIFIER_SIGALGS(sha3_384, 7);
-ENCODE_ALGORITHMIDENTIFIER_SIGALGS(sha3_512, 8);
-
-#define MD_CASE(name) \
- case NID_##name: \
- *len = sizeof(algorithmidentifier_##name##_der); \
- return algorithmidentifier_##name##_der
-
-const unsigned char *dsa_algorithmidentifier_encoding(int md_nid, size_t *len)
-{
- switch (md_nid) {
- MD_CASE(sha1);
- MD_CASE(sha224);
- MD_CASE(sha256);
- MD_CASE(sha384);
- MD_CASE(sha512);
- MD_CASE(sha3_224);
- MD_CASE(sha3_256);
- MD_CASE(sha3_384);
- MD_CASE(sha3_512);
- default:
- return NULL;
- }
-}
diff --git a/crypto/ec/build.info b/crypto/ec/build.info
index 4494ce7a66..8f12e2e39e 100644
--- a/crypto/ec/build.info
+++ b/crypto/ec/build.info
@@ -51,7 +51,7 @@ $COMMON=ec_lib.c ecp_smpl.c ecp_mont.c ecp_nist.c ec_cvt.c ec_mult.c \
ecdsa_ossl.c ecdsa_sign.c ecdsa_vrf.c curve25519.c \
curve448/arch_32/f_impl.c curve448/f_generic.c curve448/scalar.c \
curve448/curve448_tables.c curve448/eddsa.c curve448/curve448.c \
- $ECASM ecdsa_aid.c ec_backend.c ecx_backend.c
+ $ECASM ec_backend.c ecx_backend.c
SOURCE[../../libcrypto]=$COMMON ec_ameth.c ec_pmeth.c ecx_meth.c ecx_key.c \
ec_err.c ecdh_kdf.c eck_prn.c ec_evp_lib.c
SOURCE[../../providers/libfips.a]=$COMMON
diff --git a/crypto/ec/ecdsa_aid.c b/crypto/ec/ecdsa_aid.c
deleted file mode 100644
index 01bca40f8c..0000000000
--- a/crypto/ec/ecdsa_aid.c
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * 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 <openssl/objects.h>
-#include "crypto/ec.h"
-
-#define ASN1_SEQUENCE 0x30
-#define ASN1_OID 0x06
-#define OID_FIRST(a, b) a * 40 + b
-#define DER_840() 0x86, 0x48 /* DER encoding of number 840 is 2 bytes */
-#define DER_10045() 0xCE, 0x3D /* DER encoding of number 10045 is 2 bytes */
-#define SHA1_SZ 7
-#define SHA2_SZ 8
-#define SHA3_SZ 9
-
-/*
- * -- RFC 3279
- * ansi-X9-62 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) 10045 }
- * id-ecSigType OBJECT IDENTIFIER ::= { ansi-X9-62 signatures(4) }
- *
- * ecdsa-with-SHA1 OBJECT IDENTIFIER ::= { id-ecSigType 1 }
- */
-#define ENCODE_ALGORITHMIDENTIFIER_SHA1(name) \
-static const unsigned char algorithmidentifier_##name##_der[] = { \
- ASN1_SEQUENCE, 2 + SHA1_SZ, \
- ASN1_OID, SHA1_SZ, OID_FIRST(1, 2), DER_840(), DER_10045(), 4, 1 \
-}
-
-/*
- * -- RFC 5758
- *
- * ecdsa-with-SHA224 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
- * us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 1 }
- *
- * ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
- * us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 2 }
- *
- * ecdsa-with-SHA384 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
- * us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 3 }
- *
- * ecdsa-with-SHA512 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
- * us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 4 }
- */
-#define ENCODE_ALGORITHMIDENTIFIER_SHA2(name, n) \
-static const unsigned char algorithmidentifier_##name##_der[] = { \
- ASN1_SEQUENCE, 2 + SHA2_SZ, \
- ASN1_OID, SHA2_SZ, OID_FIRST(1, 2), DER_840(), DER_10045(), 4, 3, n \
-}
-
-/*
- * https://csrc.nist.gov/projects/computer-security-objects-register/algorithm-registration
- *
- * sigAlgs OBJECT IDENTIFIER ::= { 2 16 840 1 101 3 4 3 }
- *
- * id-ecdsa-with-sha3-224 ::= { sigAlgs 9 }
- * id-ecdsa-with-sha3-256 ::= { sigAlgs 10 }
- * id-ecdsa-with-sha3-384 ::= { sigAlgs 11 }
- * id-ecdsa-with-sha3-512 ::= { sigAlgs 12 }
- */
-#define ENCODE_ALGORITHMIDENTIFIER_SHA3(name, n) \
-static const unsigned char algorithmidentifier_##name##_der[] = { \
- ASN1_SEQUENCE, 2 + SHA3_SZ, \
- ASN1_OID, SHA3_SZ, OID_FIRST(2, 16), DER_840(), 1, 101, 3, 4, 3, n \
-}
-
-ENCODE_ALGORITHMIDENTIFIER_SHA1(sha1);
-ENCODE_ALGORITHMIDENTIFIER_SHA2(sha224, 1);
-ENCODE_ALGORITHMIDENTIFIER_SHA2(sha256, 2);
-ENCODE_ALGORITHMIDENTIFIER_SHA2(sha384, 3);
-ENCODE_ALGORITHMIDENTIFIER_SHA2(sha512, 4);
-ENCODE_ALGORITHMIDENTIFIER_SHA3(sha3_224, 9);
-ENCODE_ALGORITHMIDENTIFIER_SHA3(sha3_256, 10);
-ENCODE_ALGORITHMIDENTIFIER_SHA3(sha3_384, 11);
-ENCODE_ALGORITHMIDENTIFIER_SHA3(sha3_512, 12);
-/* TODO - Add SHAKE OIDS when they are standardized */
-
-#define MD_CASE(name) \
- case NID_##name: \
- *len = sizeof(algorithmidentifier_##name##_der); \
- return algorithmidentifier_##name##_der
-
-const unsigned char *ecdsa_algorithmidentifier_encoding(int md_nid, size_t *len)
-{
- switch (md_nid) {
- MD_CASE(sha1);
- MD_CASE(sha224);
- MD_CASE(sha256);
- MD_CASE(sha384);
- MD_CASE(sha512);
- MD_CASE(sha3_224);
- MD_CASE(sha3_256);
- MD_CASE(sha3_384);
- MD_CASE(sha3_512);
- default:
- return NULL;
- }
-}
diff --git a/crypto/rsa/build.info b/crypto/rsa/build.info
index 7921202739..0c9e46684c 100644
--- a/crypto/rsa/build.info
+++ b/crypto/rsa/build.info
@@ -1,6 +1,6 @@
LIBS=../../libcrypto
-$COMMON=rsa_ossl.c rsa_gen.c rsa_lib.c rsa_sign.c rsa_aid.c rsa_pk1.c \
+$COMMON=rsa_ossl.c rsa_gen.c rsa_lib.c rsa_sign.c rsa_pk1.c \
rsa_none.c rsa_oaep.c rsa_chk.c rsa_pss.c rsa_x931.c rsa_crpt.c \
rsa_x931g.c rsa_sp800_56b_gen.c rsa_sp800_56b_check.c rsa_backend.c \
rsa_mp_names.c
diff --git a/crypto/rsa/rsa_aid.c b/crypto/rsa/rsa_aid.c
deleted file mode 100644
index 4b4d3a62f1..0000000000
--- a/crypto/rsa/rsa_aid.c
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * 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 <openssl/objects.h>
-#include "crypto/rsa.h"
-
-#define ASN1_SEQUENCE 0x30
-#define ASN1_OID 0x06
-
-/*
- * -- RFC 2313
- * pkcs-1 OBJECT IDENTIFIER ::= {
- * iso(1) member-body(2) US(840) rsadsi(113549) pkcs(1) 1
- * }
- */
-
-/*
- * -- RFC 3279
- * md2WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 2 }
- * md5WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 4 }
- * sha1WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 5 }
- */
-#define ENCODE_ALGORITHMIDENTIFIER_PKCS1(name, n) \
- static const unsigned char algorithmidentifier_##name##_der[] = { \
- ASN1_SEQUENCE, 0x0b, \
- ASN1_OID, 0x09, 1 * 40 + 2, 134, 72, 134, 247, 13, 1, 1, n \
-}
-#ifndef FIPS_MODE
-ENCODE_ALGORITHMIDENTIFIER_PKCS1(md2, 2);
-ENCODE_ALGORITHMIDENTIFIER_PKCS1(md5, 4);
-#endif
-ENCODE_ALGORITHMIDENTIFIER_PKCS1(sha1, 5);
-
-/*
- * -- RFC 4055
- * sha224WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 14 }
- * sha256WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 11 }
- * sha384WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 12 }
- * sha512WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 13 }
- */
-ENCODE_ALGORITHMIDENTIFIER_PKCS1(sha224, 14);
-ENCODE_ALGORITHMIDENTIFIER_PKCS1(sha256, 11);
-ENCODE_ALGORITHMIDENTIFIER_PKCS1(sha384, 12);
-ENCODE_ALGORITHMIDENTIFIER_PKCS1(sha512, 13);
-
-/*
- * -- https://csrc.nist.gov/projects/computer-security-objects-register/algorithm-registration
- *
- * sigAlgs OBJECT IDENTIFIER ::= { 2 16 840 1 101 3 4 3 }
- *
- * id-rsassa-pkcs1-v1_5-with-sha3-224 ::= { sigAlgs 13 }
- * id-rsassa-pkcs1-v1_5-with-sha3-256 ::= { sigAlgs 14 }
- * id-rsassa-pkcs1-v1_5-with-sha3-384 ::= { sigAlgs 15 }
- * id-rsassa-pkcs1-v1_5-with-sha3-512 ::= { sigAlgs 16 }
- */
-#define ENCODE_ALGORITHMIDENTIFIER_SIGALGS(name, n) \
- static const unsigned char algorithmidentifier_##name##_der[] = { \
- ASN1_SEQUENCE, 0x0c, \
- ASN1_OID, 0x0a, 1 * 40 + 2, 16, 134, 72, 1, 101, 3, 4, 3, n \
-}
-ENCODE_ALGORITHMIDENTIFIER_SIGALGS(sha3_224, 13);
-ENCODE_ALGORITHMIDENTIFIER_SIGALGS(sha3_256, 14);
-ENCODE_ALGORITHMIDENTIFIER_SIGALGS(sha3_384, 15);
-ENCODE_ALGORITHMIDENTIFIER_SIGALGS(sha3_512, 16);
-
-#define MD_CASE(name) \
- case NID_##name: \
- *len = sizeof(algorithmidentifier_##name##_der); \
- return algorithmidentifier_##name##_der
-
-const unsigned char *rsa_algorithmidentifier_encoding(int md_nid, size_t *len)
-{
- switch (md_nid) {
-#ifndef FIPS_MODE
- MD_CASE(md2);
- MD_CASE(md5);
-#endif
- MD_CASE(sha1);
- MD_CASE(sha224);
- MD_CASE(sha256);
- MD_CASE(sha384);
- MD_CASE(sha512);
- MD_CASE(sha3_224);
- MD_CASE(sha3_256);
- MD_CASE(sha3_384);
- MD_CASE(sha3_512);
- default:
- return NULL;
- }
-}
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
diff --git a/include/internal/der.h b/include/internal/der.h
new file mode 100644
index 0000000000..118aa9857c
--- /dev/null
+++ b/include/internal/der.h
@@ -0,0 +1,84 @@
+/*
+ * 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 <openssl/bn.h>
+#include "internal/packet.h"
+
+/*
+ * NOTE: X.690 numbers the identifier octet bits 1 to 8.
+ * We use the same numbering in comments here.
+ */
+
+/* Well known primitive tags */
+
+/*
+ * DER UNIVERSAL tags, occupying bits 1-5 in the DER identifier byte
+ * These are only valid for the UNIVERSAL class. With the other classes,
+ * these bits have a different meaning.
+ */
+#define DER_P_EOC 0 /* BER End Of Contents tag */
+#define DER_P_BOOLEAN 1
+#define DER_P_INTEGER 2
+#define DER_P_BIT_STRING 3
+#define DER_P_OCTET_STRING 4
+#define DER_P_NULL 5
+#define DER_P_OBJECT 6
+#define DER_P_OBJECT_DESCRIPTOR 7
+#define DER_P_EXTERNAL 8
+#define DER_P_REAL 9
+#define DER_P_ENUMERATED 10
+#define DER_P_UTF8STRING 12
+#define DER_P_SEQUENCE 16
+#define DER_P_SET 17
+#define DER_P_NUMERICSTRING 18
+#define DER_P_PRINTABLESTRING 19
+#define DER_P_T61STRING 20
+#define DER_P_VIDEOTEXSTRING 21
+#define DER_P_IA5STRING 22
+#define DER_P_UTCTIME 23
+#define DER_P_GENERALIZEDTIME 24
+#define DER_P_GRAPHICSTRING 25
+#define DER_P_ISO64STRING 26
+#define DER_P_GENERALSTRING 27
+#define DER_P_UNIVERSALSTRING 28
+#define DER_P_BMPSTRING 30
+
+/* DER Flags, occupying bit 6 in the DER identifier byte */
+#define DER_F_PRIMITIVE 0x00
+#define DER_F_CONSTRUCTED 0x20
+
+/* DER classes tags, occupying bits 7-8 in the DER identifier byte */
+#define DER_C_UNIVERSAL 0x00
+#define DER_C_APPLICATION 0x40
+#define DER_C_CONTEXT 0x80
+#define DER_C_PRIVATE 0xC0
+
+/*
+ * Run-time constructors.
+ *
+ * They all construct DER backwards, so care should be taken to use them
+ * that way.
+ */
+
+/* This can be used for all items that don't have a context */
+#define DER_NO_CONTEXT -1
+
+int DER_w_precompiled(WPACKET *pkt, int tag,
+ const unsigned char *precompiled, size_t precompiled_n);
+
+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);
+
+/*
+ * All constructors for constructed elements have a begin and a end function
+ */
+int DER_w_begin_sequence(WPACKET *pkt, int tag);
+int DER_w_end_sequence(WPACKET *pkt, int tag);
diff --git a/providers/common/build.info b/providers/common/build.info
index ccc99e515b..b6495d343a 100644
--- a/providers/common/build.info
+++ b/providers/common/build.info
@@ -1,3 +1,5 @@
+SUBDIRS=der
+
SOURCE[../libcommon.a]=provider_err.c bio_prov.c
$FIPSCOMMON=provider_util.c
SOURCE[../libnonfips.a]=$FIPSCOMMON nid_to_name.c
diff --git a/providers/common/der/DSA.asn1 b/providers/common/der/DSA.asn1
new file mode 100644
index 0000000000..84b677a40f
--- /dev/null
+++ b/providers/common/der/DSA.asn1
@@ -0,0 +1,29 @@
+-- -------------------------------------------------------------------
+-- Taken from RFC 3279, 3 ASN.1 Module
+-- (https://www.rfc-editor.org/rfc/rfc3279.html#section-3)
+
+-- OID for DSA public key
+
+id-dsa OBJECT IDENTIFIER ::= {
+ iso(1) member-body(2) us(840) x9-57(10040) x9algorithm(4) 1 }
+
+-- OID for DSA signature generated with SHA-1 hash
+
+id-dsa-with-sha1 OBJECT IDENTIFIER ::= {
+ iso(1) member-body(2) us(840) x9-57 (10040) x9algorithm(4) 3 }
+
+
+-- -------------------------------------------------------------------
+-- Taken from https://csrc.nist.gov/projects/computer-security-objects-register/algorithm-registration
+
+sigAlgs OBJECT IDENTIFIER ::= { 2 16 840 1 101 3 4 3 }
+
+id-dsa-with-sha224 OBJECT IDENTIFIER ::= { sigAlgs 1 }
+id-dsa-with-sha256 OBJECT IDENTIFIER ::= { sigAlgs 2 }
+id-dsa-with-sha384 OBJECT IDENTIFIER ::= { sigAlgs 3 }
+id-dsa-with-sha512 OBJECT IDENTIFIER ::= { sigAlgs 4 }
+
+id-dsa-with-sha3-224 OBJECT IDENTIFIER ::= { sigAlgs 5 }
+id-dsa-with-sha3-256 OBJECT IDENTIFIER ::= { sigAlgs 6 }
+id-dsa-with-sha3-384 OBJECT IDENTIFIER ::= { sigAlgs 7 }
+id-dsa-with-sha3-512 OBJECT IDENTIFIER ::= { sigAlgs 8 }
diff --git a/providers/common/der/EC.asn1 b/providers/common/der/EC.asn1
new file mode 100644
index 0000000000..d55a69273f
--- /dev/null
+++ b/providers/common/der/EC.asn1
@@ -0,0 +1,83 @@
+-- -------------------------------------------------------------------
+-- Taken from RFC 3279, 3 ASN.1 Module
+-- (https://www.rfc-editor.org/rfc/rfc3279.html#section-3)
+
+ansi-X9-62 OBJECT IDENTIFIER ::= {
+ iso(1) member-body(2) us(840) 10045 }
+
+-- Arc for ECDSA signature OIDS
+
+id-ecSigType OBJECT IDENTIFIER ::= { ansi-X9-62 signatures(4) }
+
+-- OID for ECDSA signatures with SHA-1
+
+ecdsa-with-SHA1 OBJECT IDENTIFIER ::= { id-ecSigType 1 }
+
+id-publicKeyType OBJECT IDENTIFIER ::= { ansi-X9-62 keyType(2) }
+
+id-ecPublicKey OBJECT IDENTIFIER ::= { id-publicKeyType 1 }
+
+-- Named Elliptic Curves in ANSI X9.62.
+
+ellipticCurve OBJECT IDENTIFIER ::= { ansi-X9-62 curves(3) }
+
+c-TwoCurve OBJECT IDENTIFIER ::= {
+ ellipticCurve characteristicTwo(0) }
+
+c2pnb163v1 OBJECT IDENTIFIER ::= { c-TwoCurve 1 }
+c2pnb163v2 OBJECT IDENTIFIER ::= { c-TwoCurve 2 }
+c2pnb163v3 OBJECT IDENTIFIER ::= { c-TwoCurve 3 }
+c2pnb176w1 OBJECT IDENTIFIER ::= { c-TwoCurve 4 }
+c2tnb191v1 OBJECT IDENTIFIER ::= { c-TwoCurve 5 }
+c2tnb191v2 OBJECT IDENTIFIER ::= { c-TwoCurve 6 }
+c2tnb191v3 OBJECT IDENTIFIER ::= { c-TwoCurve 7 }
+c2onb191v4 OBJECT IDENTIFIER ::= { c-TwoCurve 8 }
+c2onb191v5 OBJECT IDENTIFIER ::= { c-TwoCurve 9 }
+c2pnb208w1 OBJECT IDENTIFIER ::= { c-TwoCurve 10 }
+c2tnb239v1 OBJECT IDENTIFIER ::= { c-TwoCurve 11 }
+c2tnb239v2 OBJECT IDENTIFIER ::= { c-TwoCurve 12 }
+c2tnb239v3 OBJECT IDENTIFIER ::= { c-TwoCurve 13 }
+c2onb239v4 OBJECT IDENTIFIER ::= { c-TwoCurve 14 }
+c2onb239v5 OBJECT IDENTIFIER ::= { c-TwoCurve 15 }
+c2pnb272w1 OBJECT IDENTIFIER ::= { c-TwoCurve 16 }
+c2pnb304w1 OBJECT IDENTIFIER ::= { c-TwoCurve 17 }
+c2tnb359v1 OBJECT IDENTIFIER ::= { c-TwoCurve 18 }
+c2pnb368w1 OBJECT IDENTIFIER ::= { c-TwoCurve 19 }
+c2tnb431r1 OBJECT IDENTIFIER ::= { c-TwoCurve 20 }
+
+primeCurve OBJECT IDENTIFIER ::= { ellipticCurve prime(1) }
+
+prime192v1 OBJECT IDENTIFIER ::= { primeCurve 1 }
+prime192v2 OBJECT IDENTIFIER ::= { primeCurve 2 }
+prime192v3 OBJECT IDENTIFIER ::= { primeCurve 3 }
+prime239v1 OBJECT IDENTIFIER ::= { primeCurve 4 }
+prime239v2 OBJECT IDENTIFIER ::= { primeCurve 5 }
+prime239v3 OBJECT IDENTIFIER ::= { primeCurve 6 }
+prime256v1 OBJECT IDENTIFIER ::= { primeCurve 7 }
+
+-- -------------------------------------------------------------------
+-- Taken from RFC 5758, 3.2. ECDSA Signature Algorithm
+-- (https://www.rfc-editor.org/rfc/rfc5758.html#section-3.2)
+
+ecdsa-with-SHA224 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+ us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 1 }
+
+ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+ us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 2 }
+
+ecdsa-with-SHA384 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+ us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 3 }
+
+ecdsa-with-SHA512 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+ us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 4 }
+
+-- -------------------------------------------------------------------
+-- Taken from https://csrc.nist.gov/projects/computer-security-objects-register/algorithm-registration
+
+sigAlgs OBJECT IDENTIFIER ::= { 2 16 840 1 101 3 4 3 }
+
+id-ecdsa-with-sha3-224 OBJECT IDENTIFIER ::= { sigAlgs 9 }
+id-ecdsa-with-sha3-256 OBJECT IDENTIFIER ::= { sigAlgs 10 }
+id-ecdsa-with-sha3-384 OBJECT IDENTIFIER ::= { sigAlgs 11 }
+id-ecdsa-with-sha3-512 OBJECT IDENTIFIER ::= { sigAlgs 12 }
+
diff --git a/providers/common/der/RSA.asn1 b/providers/common/der/RSA.asn1
new file mode 100644
index 0000000000..7bce636029
--- /dev/null
+++ b/providers/common/der/RSA.asn1
@@ -0,0 +1,88 @@
+-- -------------------------------------------------------------------
+-- Taken from RFC 8017, Appendix C
+-- (https://www.rfc-editor.org/rfc/rfc8017.html#appendix-C)
+
+-- ============================
+-- Basic object identifiers
+-- ============================
+
+-- The DER encoding of this in hexadecimal is:
+-- (0x)06 08
+-- 2A 86 48 86 F7 0D 01 01
+--
+pkcs-1 OBJECT IDENTIFIER ::= {
+ iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1
+}
+
+--
+-- When rsaEncryption is used in an AlgorithmIdentifier,
+-- the parameters MUST be present and MUST be NULL.
+--
+rsaEncryption OBJECT IDENTIFIER ::= { pkcs-1 1 }
+
+--
+-- When id-RSAES-OAEP is used in an AlgorithmIdentifier, the
+-- parameters MUST be present and MUST be RSAES-OAEP-params.
+--
+id-RSAES-OAEP OBJECT IDENTIFIER ::= { pkcs-1 7 }
+
+--
+-- When id-pSpecified is used in an AlgorithmIdentifier, the
+-- parameters MUST be an OCTET STRING.
+--
+id-pSpecified OBJECT IDENTIFIER ::= { pkcs-1 9 }
+
+--
+-- When id-RSASSA-PSS is used in an AlgorithmIdentifier, the
+-- parameters MUST be present and MUST be RSASSA-PSS-params.
+--
+id-RSASSA-PSS OBJECT IDENTIFIER ::= { pkcs-1 10 }
+
+--
+-- When the following OIDs are used in an AlgorithmIdentifier,
+-- the parameters MUST be present and MUST be NULL.
+--
+md2WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 2 }
+md5WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 4 }
+sha1WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 5 }
+sha224WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 14 }
+sha256WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 11 }
+sha384WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 12 }
+sha512WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 13 }
+sha512-224WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 15 }
+sha512-256WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 16 }
+
+--
+-- This OID really belongs in a module with the secsig OIDs.
+--
+id-sha1 OBJECT IDENTIFIER ::= {
+ iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2)
+ 26
+}
+
+--
+-- OIDs for MD2 and MD5, allowed only in EMSA-PKCS1-v1_5.
+--
+id-md2 OBJECT IDENTIFIER ::= {
+ iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 2
+}
+
+id-md5 OBJECT IDENTIFIER ::= {
+ iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 5
+}
+
+--
+-- When id-mgf1 is used in an AlgorithmIdentifier, the parameters
+-- MUST be present and MUST be a HashAlgorithm, for example, sha1.
+--
+id-mgf1 OBJECT IDENTIFIER ::= { pkcs-1 8 }
+
+-- -------------------------------------------------------------------
+-- Taken from https://csrc.nist.gov/projects/computer-security-objects-register/algorithm-registration
+
+sigAlgs OBJECT IDENTIFIER ::= { 2 16 840 1 101 3 4 3 }
+
+id-rsassa-pkcs1-v1_5-with-sha3-224 OBJECT IDENTIFIER ::= { sigAlgs 13 }
+id-rsassa-pkcs1-v1_5-with-sha3-256 OBJECT IDENTIFIER ::= { sigAlgs 14 }
+id-rsassa-pkcs1-v1_5-with-sha3-384 OBJECT IDENTIFIER ::= { sigAlgs 15 }
+id-rsassa-pkcs1-v1_5-with-sha3-512 OBJECT IDENTIFIER ::= { sigAlgs 16 }
diff --git a/providers/common/der/build.info b/providers/common/der/build.info
new file mode 100644
index 0000000000..eda763ea8e
--- /dev/null
+++ b/providers/common/der/build.info
@@ -0,0 +1,25 @@
+$FIPSABLE=der_rsa.c der_dsa.c der_ec.c
+
+SOURCE[../../libfips.a]=$FIPSABLE
+SOURCE[../../libnonfips.a]=$FIPSABLE
+
+GENERATE[der_rsa.c]=der_rsa.c.in
+DEPEND[der_rsa.c]=oids_to_c.pm
+
+DEPEND[der_rsa.o]=../include/prov/der_rsa.h
+GENERATE[../include/prov/der_rsa.h]=der_rsa.h.in
+DEPEND[../include/prov/der_rsa.h]=oids_to_c.pm
+
+GENERATE[der_dsa.c]=der_dsa.c.in
+DEPEND[der_dsa.c]=oids_to_c.pm
+
+DEPEND[der_dsa.o]=../include/prov/der_dsa.h
+GENERATE[../include/prov/der_dsa.h]=der_dsa.h.in
+DEPEND[../include/prov/der_dsa.h]=oids_to_c.pm
+
+GENERATE[der_ec.c]=der_ec.c.in
+DEPEND[der_ec.c]=oids_to_c.pm
+
+DEPEND[der_ec.o]=../include/prov/der_ec.h
+GENERATE[../include/prov/der_ec.h]=der_ec.h.in
+DEPEND[../include/prov/der_ec.h]=oids_to_c.pm
diff --git a/providers/common/der/der_dsa.c.in b/providers/common/der/der_dsa.c.in
new file mode 100644
index 0000000000..28c0ba8c6c
--- /dev/null
+++ b/providers/common/der/der_dsa.c.in
@@ -0,0 +1,59 @@
+/*
+ * 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 <openssl/bn.h>
+#include <openssl/obj_mac.h>
+#include "prov/der_dsa.h"
+
+/* Well known OIDs precompiled */
+{-
+ $OUT = oids_to_c::process_leaves('providers/common/der/DSA.asn1',
+ { dir => $config{sourcedir},
+ filter => \&oids_to_c::filter_to_C });
+-}
+
+int DER_w_algorithmIdentifier_DSA(WPACKET *pkt, int tag, DSA *dsa)
+{
+ return DER_w_begin_sequence(pkt, tag)
+ /* No parameters (yet?) */
+ && DER_w_precompiled(pkt, -1, der_oid_id_dsa, sizeof(der_oid_id_dsa))
+ && DER_w_end_sequence(pkt, tag);
+}
+
+#define MD_CASE(name) \
+ case NID_##name: \
+ precompiled = der_oid_id_dsa_with_##name; \
+ precompiled_sz = sizeof(der_oid_id_dsa_with_##name); \
+ break;
+
+int DER_w_algorithmIdentifier_DSA_with(WPACKET *pkt, int tag,
+ DSA *dsa, int mdnid)
+{
+ const unsigned char *precompiled = NULL;
+ size_t precompiled_sz = 0;
+
+ switch (mdnid) {
+ MD_CASE(sha1);
+ MD_CASE(sha224);
+ MD_CASE(sha256);
+ MD_CASE(sha384);
+ MD_CASE(sha512);
+ MD_CASE(sha3_224);
+ MD_CASE(sha3_256);
+ MD_CASE(sha3_384);
+ MD_CASE(sha3_512);
+ default:
+ return 0;
+ }
+
+ return DER_w_begin_sequence(pkt, tag)
+ /* No parameters (yet?) */
+ && DER_w_precompiled(pkt, -1, precompiled, precompiled_sz)
+ && DER_w_end_sequence(pkt, tag);
+}
diff --git a/providers/common/der/der_dsa.h.in b/providers/common/der/der_dsa.h.in
new file mode 100644
index 0000000000..d9e7bf205a
--- /dev/null
+++ b/providers/common/der/der_dsa.h.in
@@ -0,0 +1,21 @@
+/*
+ * 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 "internal/der.h"
+
+/* Well known OIDs precompiled */
+{-
+ $OUT = oids_to_c::process_leaves('providers/common/der/DSA.asn1',
+ { dir => $config{sourcedir},
+ filter => \&oids_to_c::filter_to_H });
+-}
+
+int DER_w_algorithmIdentifier_DSA(WPACKET *pkt, int tag, DSA *dsa);
+int DER_w_algorithmIdentifier_DSA_with(WPACKET *pkt, int tag,
+ DSA *dsa, int mdnid);
diff --git a/providers/common/der/der_ec.c.in b/providers/common/der/der_ec.c.in
new file mode 100644
index 0000000000..a617651e4e
--- /dev/null
+++ b/providers/common/der/der_ec.c.in
@@ -0,0 +1,67 @@
+/*
+ * 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 <openssl/bn.h>
+#include <openssl/obj_mac.h>
+#include "prov/der_ec.h"
+
+/* Well known OIDs precompiled */
+{-
+ $OUT = oids_to_c::process_leaves('providers/common/der/EC.asn1',
+ { dir => $config{sourcedir},
+ filter => \&oids_to_c::filter_to_C });
+-}
+
+int DER_w_algorithmIdentifier_EC(WPACKET *pkt, int cont, EC_KEY *ec)
+{
+ return DER_w_begin_sequence(pkt, cont)
+ /* No parameters (yet?) */
+ && DER_w_precompiled(pkt, -1, der_oid_id_ecPublicKey,
+ sizeof(der_oid_id_ecPublicKey))
+ && DER_w_end_sequence(pkt, cont);
+}
+
+/* Aliases so we can have a uniform MD_CASE */
+#define der_oid_id_ecdsa_with_sha1 der_oid_ecdsa_with_SHA1
+#define der_oid_id_ecdsa_with_sha224 der_oid_ecdsa_with_SHA224
+#define der_oid_id_ecdsa_with_sha256 der_oid_ecdsa_with_SHA256
+#define der_oid_id_ecdsa_with_sha384 der_oid_ecdsa_with_SHA384
+#define der_oid_id_ecdsa_with_sha512 der_oid_ecdsa_with_SHA512
+
+#define MD_CASE(name) \
+ case NID_##name: \
+ precompiled = der_oid_id_ecdsa_with_##name; \
+ precompiled_sz = sizeof(der_oid_id_ecdsa_with_##name); \
+ break;
+
+int DER_w_algorithmIdentifier_ECDSA_with(WPACKET *pkt, int cont,
+ EC_KEY *ec, int mdnid)
+{
+ const unsigned char *precompiled = NULL;
+ size_t precompiled_sz = 0;
+
+ switch (mdnid) {
+ MD_CASE(sha1);
+ MD_CASE(sha224);
+ MD_CASE(sha256);
+ MD_CASE(sha384);
+ MD_CASE(sha512);
+ MD_CASE(sha3_224);
+ MD_CASE(sha3_256);
+ MD_CASE(sha3_384);
+ MD_CASE(sha3_512);
+ default:
+ return 0;
+ }
+
+ return DER_w_begin_sequence(pkt, cont)
+ /* No parameters (yet?) */
+ && DER_w_precompiled(pkt, -1, precompiled, precompiled_sz)
+ && DER_w_end_sequence(pkt, cont);
+}
diff --git a/providers/common/der/der_ec.h.in b/providers/common/der/der_ec.h.in
new file mode 100644
index 0000000000..24f153cd8f
--- /dev/null
+++ b/providers/common/der/der_ec.h.in
@@ -0,0 +1,21 @@
+/*
+ * 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 "internal/der.h"
+
+/* Well known OIDs precompiled */
+{-
+ $OUT = oids_to_c::process_leaves('providers/common/der/EC.asn1',
+ { dir => $config{sourcedir},
+ filter => \&oids_to_c::filter_to_H });
+-}
+
+int DER_w_algorithmIdentifier_EC(WPACKET *pkt, int cont, EC_KEY *ec);
+int DER_w_algorithmIdentifier_ECDSA_with(WPACKET *pkt, int cont,
+ EC_KEY *ec, int mdnid);
diff --git a/providers/common/der/der_rsa.c.in b/providers/common/der/der_rsa.c.in
new file mode 100644
index 0000000000..fb936d2966
--- /dev/null
+++ b/providers/common/der/der_rsa.c.in
@@ -0,0 +1,74 @@
+/*
+ * 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 <openssl/bn.h>
+#include <openssl/obj_mac.h>
+#include "prov/der_rsa.h"
+
+/* Well known OIDs precompiled */
+{-
+ $OUT = oids_to_c::process_leaves('providers/common/der/RSA.asn1',
+ { dir => $config{sourcedir},
+ filter => \&oids_to_c::filter_to_C });
+-}
+
+int DER_w_algorithmIdentifier_RSA(WPACKET *pkt, int tag, RSA *rsa)
+{
+ return DER_w_begin_sequence(pkt, tag)
+ /* No parameters (yet?) */
+ && DER_w_precompiled(pkt, -1, der_oid_rsaEncryption,
+ sizeof(der_oid_rsaEncryption))
+ && DER_w_end_sequence(pkt, tag);
+}
+
+/* Aliases so we can have a uniform MD_CASE */
+#define der_oid_sha3_224WithRSAEncryption \
+ der_oid_id_rsassa_pkcs1_v1_5_with_sha3_224
+#define der_oid_sha3_256WithRSAEncryption \
+ der_oid_id_rsassa_pkcs1_v1_5_with_sha3_256
+#define der_oid_sha3_384WithRSAEncryption \
+ der_oid_id_rsassa_pkcs1_v1_5_with_sha3_384
+#define der_oid_sha3_512WithRSAEncryption \
+ der_oid_id_rsassa_pkcs1_v1_5_with_sha3_512
+
+#define MD_CASE(name) \
+ case NID_##name: \
+ precompiled = der_oid_##name##WithRSAEncryption; \
+ precompiled_sz = sizeof(der_oid_##name##WithRSAEncryption); \
+ break;
+
+int DER_w_algorithmIdentifier_RSA_with(WPACKET *pkt, int tag,
+ RSA *rsa, int mdnid)
+{
+ const unsigned char *precompiled = NULL;
+ size_t precompiled_sz = 0;
+
+ switch (mdnid) {
+#ifndef FIPS_MODE
+ MD_CASE(md2);
+ MD_CASE(md5);
+#endif
+ MD_CASE(sha1);
+ MD_CASE(sha224);
+ MD_CASE(sha256);
+ MD_CASE(sha384);
+ MD_CASE(sha512);
+ MD_CASE(sha3_224);
+ MD_CASE(sha3_256);
+ MD_CASE(sha3_384);
+ MD_CASE(sha3_512);
+ default:
+ return 0;
+ }
+
+ return DER_w_begin_sequence(pkt, tag)
+ /* No parameters (yet?) */
+ && DER_w_precompiled(pkt, -1, precompiled, precompiled_sz)
+ && DER_w_end_sequence(pkt, tag);
+}
diff --git a/providers/common/der/der_rsa.h.in b/providers/common/der/der_rsa.h.in
new file mode 100644
index 0000000000..3f7cc0e029
--- /dev/null
+++ b/providers/common/der/der_rsa.h.in
@@ -0,0 +1,21 @@
+/*
+ * 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 "internal/der.h"
+
+/* Well known OIDs precompiled */
+{-
+ $OUT = oids_to_c::process_leaves('providers/common/der/RSA.asn1',
+ { dir => $config{sourcedir},
+ filter => \&oids_to_c::filter_to_H });
+-}
+
+int DER_w_algorithmIdentifier_RSA(WPACKET *pkt, int tag, RSA *rsa);
+int DER_w_algorithmIdentifier_RSA_with(WPACKET *pkt, int tag,
+ RSA *rsa, int mdnid);
diff --git a/providers/common/der/oids_to_c.pm b/providers/common/der/oids_to_c.pm
new file mode 100644
index 0000000000..64e6c07df3
--- /dev/null
+++ b/providers/common/der/oids_to_c.pm
@@ -0,0 +1,111 @@
+#! /usr/bin/env perl
+# 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
+
+use strict;
+use warnings;
+
+package oids_to_c;
+
+use Carp;
+use File::Spec;
+use OpenSSL::OID;
+
+my $OID_name_re = qr/([a-z](?:[-_A-Za-z0-9]*[A-Za-z0-9])?)/;
+my $OID_value_re = qr/(\{.*?\})/s;
+my $OID_def_re = qr/
+ ${OID_name_re} \s+ OBJECT \s+ IDENTIFIER \s*
+ ::=
+ \s* ${OID_value_re}
+ /x;
+
+use Data::Dumper;
+
+sub filter_to_H {
+ my ($name, $comment) = @{ shift() };
+ my @oid_nums = @_;
+
+ (my $C_name = $name) =~ s|-|_|g;
+ my $C_bytes_size = 2 + scalar @_;
+
+ return <<"_____";
+extern const unsigned char der_oid_${C_name}[$C_bytes_size];
+_____
+}
+
+sub filter_to_C {
+ my ($name, $comment) = @{ shift() };
+ my @oid_nums = @_;
+ my $oid_size = scalar @oid_nums;
+
+ croak "Unsupported OID size (>127 bytes)" if $oid_size > 127;
+
+ (my $C_comment = $comment) =~ s|^| * |msg;
+ $C_comment = "\n/*\n${C_comment}\n */" if $C_comment ne '';
+ (my $C_name = $name) =~ s|-|_|g;
+ my $C_bytes_size = 2 + $oid_size;
+ my $C_bytes = join(', ', map { sprintf("0x%02X", $_) } @oid_nums );
+
+ return <<"_____";
+$C_comment
+#define DER_OID_V_${C_name} DER_P_OBJECT, $oid_size, ${C_bytes}
+#define DER_OID_SZ_${C_name} ${C_bytes_size}
+const unsigned char der_oid_${C_name}[DER_OID_SZ_${C_name}] = {
+ DER_OID_V_${C_name}
+};
+_____
+}
+
+sub _process {
+ my %opts = %{ pop @_ } if ref $_[$#_] eq 'HASH';
+
+ # To maintain input order
+ my @OID_names = ();
+
+ foreach my $file (@_) {
+ my $input = File::Spec->catfile($opts{dir}, $file);
+ open my $fh, $input or die "Reading $input: $!\n";
+
+ my $text = join('',
+ map {
+ s|--.*(\R)$|$1|;
+ $_;
+ } <$fh>);
+ # print STDERR "-----BEGIN DEBUG-----\n";
+ # print STDERR $text;
+ # print STDERR "-----END DEBUG-----\n";
+ use re 'debugcolor';
+ while ($text =~ m/${OID_def_re}/sg) {
+ my $comment = $&;
+ my $name = $1;
+ my $value = $2;
+
+ # print STDERR "-----BEGIN DEBUG $name-----\n";
+ # print STDERR $value,"\n";
+ # print STDERR "-----END DEBUG $name-----\n";
+ register_oid($name, $value);
+ push @OID_names, [ $name, $comment ];
+ }
+ }
+
+ return @OID_names;
+}
+
+sub process_leaves {
+ my %opts = %{ $_[$#_] } if ref $_[$#_] eq 'HASH';
+ my @OID_names = _process @_;
+
+ my $text = '';
+ my %leaves = map { $_ => 1 } registered_oid_leaves;
+ foreach (grep { defined $leaves{$_->[0]} } @OID_names) {
+ my $lines = $opts{filter}->($_, encode_oid($_->[0]));
+ $text .= $lines;
+ }
+ return $text;
+}
+
+1;
diff --git a/providers/implementations/signature/build.info b/providers/implementations/signature/build.info
index 6f19ca83f6..dbe0876a0e 100644
--- a/providers/implementations/signature/build.info
+++ b/providers/implementations/signature/build.info
@@ -16,3 +16,7 @@ ENDIF
SOURCE[../../libfips.a]=rsa.c
SOURCE[../../libnonfips.a]=rsa.c
+
+DEPEND[rsa.o]=../../common/include/prov/der_rsa.h
+DEPEND[dsa.o]=../../common/include/prov/der_dsa.h
+DEPEND[ecdsa.o]=../../common/include/prov/der_ec.h
diff --git a/providers/implementations/signature/dsa.c b/providers/implementations/signature/dsa.c
index 92c3b571c2..30147aa163 100644
--- a/providers/implementations/signature/dsa.c
+++ b/providers/implementations/signature/dsa.c
@@ -25,11 +25,13 @@
#include <openssl/err.h>
#include "internal/nelem.h"
#include "internal/sizes.h"
+#include "internal/cryptlib.h"
#include "prov/providercommonerr.h"
#include "prov/implementations.h"
#include "prov/providercommonerr.h"
#include "prov/provider_ctx.h"
#include "crypto/dsa.h"
+#include "prov/der_dsa.h"
static OSSL_OP_signature_newctx_fn dsa_newctx;
static OSSL_OP_signature_sign_init_fn dsa_signature_init;
@@ -74,7 +76,8 @@ typedef struct {
char mdname[OSSL_MAX_NAME_SIZE];
/* The Algorithm Identifier of the combined signature algorithm */
- unsigned char aid[OSSL_MAX_ALGORITHM_ID_SIZE];
+ unsigned char aid_buf[OSSL_MAX_ALGORITHM_ID_SIZE];
+ unsigned char *aid;
size_t aid_len;
/* main digest */
@@ -146,25 +149,35 @@ static int dsa_setup_md(PROV_DSA_CTX *ctx,
if (mdname != NULL) {
EVP_MD *md = EVP_MD_fetch(ctx->libctx, mdname, mdprops);
int md_nid = dsa_get_md_nid(md);
- size_t algorithmidentifier_len = 0;
- const unsigned char *algorithmidentifier;
+ WPACKET pkt;
- EVP_MD_free(ctx->md);
- ctx->md = NULL;
- ctx->mdname[0] = '\0';
-
- algorithmidentifier =
- dsa_algorithmidentifier_encoding(md_nid, &algorithmidentifier_len);
-
- if (algorithmidentifier == NULL) {
+ if (md == NULL || md_nid == NID_undef) {
EVP_MD_free(md);
return 0;
}
+ EVP_MD_CTX_free(ctx->mdctx);
+ EVP_MD_free(ctx->md);
+
+ /*
+ * TODO(3.0) Should we care about DER writing errors?
+ * All it really means is that for some reason, there's no
+ * AlgorithmIdentifier to be had, but the operation itself is
+ * still valid, just as long as it's not used to construct
+ * anything that needs an AlgorithmIdentifier.
+ */
+ ctx->aid_len = 0;
+ if (WPACKET_init_der(&pkt, ctx->aid_buf, sizeof(ctx->aid_buf))
+ && DER_w_algorithmIdentifier_DSA_with(&pkt, -1, ctx->dsa, md_nid)
+ && WPACKET_finish(&pkt)) {
+ WPACKET_get_total_written(&pkt, &ctx->aid_len);
+ ctx->aid = WPACKET_get_curr(&pkt);
+ }
+ WPACKET_cleanup(&pkt);
+
+ ctx->mdctx = NULL;
ctx->md = md;
OPENSSL_strlcpy(ctx->mdname, mdname, sizeof(ctx->mdname));
- memcpy(ctx->aid, algorithmidentifier, algorithmidentifier_len);
- ctx->aid_len = algorithmidentifier_len;
}
return 1;
}
diff --git a/providers/implementations/signature/ecdsa.c b/providers/implementations/signature/ecdsa.c
index 733c0a23a5..e05830f500 100644
--- a/providers/implementations/signature/ecdsa.c
+++ b/providers/implementations/signature/ecdsa.c
@@ -23,10 +23,12 @@
#include <openssl/err.h>
#include "internal/nelem.h"
#include "internal/sizes.h"
+#include "internal/cryptlib.h"
#include "prov/providercommonerr.h"
#include "prov/implementations.h"
#include "prov/provider_ctx.h"
#include "crypto/ec.h"
+#include "prov/der_ec.h"
static OSSL_OP_signature_newctx_fn ecdsa_newctx;
static OSSL_OP_signature_sign_init_fn ecdsa_signature_init;
@@ -62,7 +64,8 @@ typedef struct {
char mdname[OSSL_MAX_NAME_SIZE];
/* The Algorithm Identifier of the combined signature algorithm */
- unsigned char aid[OSSL_MAX_ALGORITHM_ID_SIZE];
+ unsigned char aid_buf[OSSL_MAX_ALGORITHM_ID_SIZE];
+ unsigned char *aid;
size_t aid_len;
size_t mdsize;
@@ -203,8 +206,8 @@ static int ecdsa_digest_signverify_init(void *vctx, const char *mdname,
const char *props, void *ec)
{
PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx;
- size_t algorithmidentifier_len = 0;
- const unsigned char *algorithmidentifier;
+ int md_nid = NID_undef;
+ WPACKET pkt;
free_md(ctx);
@@ -212,10 +215,7 @@ static int ecdsa_digest_signverify_init(void *vctx, const char *mdname,
return 0;
ctx->md = EVP_MD_fetch(ctx->libctx, mdname, props);
- algorithmidentifier =
- ecdsa_algorithmidentifier_encoding(get_md_nid(ctx->md),
- &algorithmidentifier_len);
- if (algorithmidentifier == NULL)
+ if ((md_nid = get_md_nid(ctx->md)) == NID_undef)
goto error;
ctx->mdsize = EVP_MD_size(ctx->md);
@@ -223,8 +223,21 @@ static int ecdsa_digest_signverify_init(void *vctx, const char *mdname,
if (ctx->mdctx == NULL)
goto error;
- memcpy(ctx->aid, algorithmidentifier, algorithmidentifier_len);
- ctx->aid_len = algorithmidentifier_len;
+ /*
+ * TODO(3.0) Should we care about DER writing errors?
+ * All it really means is that for some reason, there's no
+ * AlgorithmIdentifier to be had, but the operation itself is
+ * still valid, just as long as it's not used to construct
+ * anything that needs an AlgorithmIdentifier.
+ */
+ ctx->aid_len = 0;
+ if (WPACKET_init_der(&pkt, ctx->aid_buf, sizeof(ctx->aid_buf))
+ && DER_w_algorithmIdentifier_ECDSA_with(&pkt, -1, ctx->ec, md_nid)
+ && WPACKET_finish(&pkt)) {
+ WPACKET_get_total_written(&pkt, &ctx->aid_len);
+ ctx->aid = WPACKET_get_curr(&pkt);
+ }
+ WPACKET_cleanup(&pkt);
if (!EVP_DigestInit_ex(ctx->mdctx, ctx->md, NULL))
goto error;
diff --git a/providers/implementations/signature/rsa.c b/providers/implementations/signature/rsa.c
index 848cbd7249..cfa76921b5 100644
--- a/providers/implementations/signature/rsa.c
+++ b/providers/implementations/signature/rsa.c
@@ -28,6 +28,7 @@
#include "prov/providercommonerr.h"
#include "prov/implementations.h"
#include "prov/provider_ctx.h"
+#include "prov/der_rsa.h"
static OSSL_OP_signature_newctx_fn rsa_newctx;
static OSSL_OP_signature_sign_init_fn rsa_signature_init;
@@ -83,7 +84,8 @@ typedef struct {
unsigned int flag_allow_md : 1;
/* The Algorithm Identifier of the combined signature agorithm */
- unsigned char aid[128];
+ unsigned char aid_buf[128];
+ unsigned char *aid;
size_t aid_len;
/* main digest */
@@ -216,35 +218,38 @@ static int rsa_setup_md(PROV_RSA_CTX *ctx, const char *mdname,
if (mdname != NULL) {
EVP_MD *md = EVP_MD_fetch(ctx->libctx, mdname, mdprops);
int md_nid = rsa_get_md_nid(md);
- size_t algorithmidentifier_len = 0;
- const unsigned char *algorithmidentifier = NULL;
+ WPACKET pkt;
- if (md == NULL)
- return 0;
-
- if (!rsa_check_padding(md_nid, ctx->pad_mode)) {
+ if (md == NULL
+ || md_nid == NID_undef
+ || !rsa_check_padding(md_nid, ctx->pad_mode)) {
EVP_MD_free(md);
return 0;
}
EVP_MD_CTX_free(ctx->mdctx);
EVP_MD_free(ctx->md);
- ctx->md = NULL;
- ctx->mdctx = NULL;
- ctx->mdname[0] = '\0';
- ctx->aid[0] = '\0';
- ctx->aid_len = 0;
- algorithmidentifier =
- rsa_algorithmidentifier_encoding(md_nid, &algorithmidentifier_len);
+ /*
+ * TODO(3.0) Should we care about DER writing errors?
+ * All it really means is that for some reason, there's no
+ * AlgorithmIdentifier to be had (consider RSA with MD5-SHA1),
+ * but the operation itself is still valid, just as long as it's
+ * not used to construct anything that needs an AlgorithmIdentifier.
+ */
+ ctx->aid_len = 0;
+ if (WPACKET_init_der(&pkt, ctx->aid_buf, sizeof(ctx->aid_buf))
+ && DER_w_algorithmIdentifier_RSA_with(&pkt, -1, ctx->rsa, md_nid)
+ && WPACKET_finish(&pkt)) {
+ WPACKET_get_total_written(&pkt, &ctx->aid_len);
+ ctx->aid = WPACKET_get_curr(&pkt);
+ }
+ WPACKET_cleanup(&pkt);
+ ctx->mdctx = NULL;
ctx->md = md;
ctx->mdnid = md_nid;
OPENSSL_strlcpy(ctx->mdname, mdname, sizeof(ctx->mdname));
- if (algorithmidentifier != NULL) {
- memcpy(ctx->aid, algorithmidentifier, algorithmidentifier_len);
- ctx->aid_len = algorithmidentifier_len;
- }
}
return 1;
diff --git a/util/missingcrypto.txt b/util/missingcrypto.txt
index dbe4ef55f9..d6d30912f3 100644
--- a/util/missingcrypto.txt
+++ b/util/missingcrypto.txt
@@ -1274,6 +1274,9 @@ WHIRLPOOL_BitUpdate(3)
WHIRLPOOL_Final(3)
WHIRLPOOL_Init(3)
WHIRLPOOL_Update(3)
+WPACKET(3)
+WPACKET_init_der(3)
+WPACKET_init_null_der(3)
X509V3_EXT_CRL_add_conf(3)
X509V3_EXT_CRL_add_nconf(3)
X509V3_EXT_REQ_add_conf(3)
diff --git a/util/perl/OpenSSL/OID.pm b/util/perl/OpenSSL/OID.pm
new file mode 100644
index 0000000000..a4d1049c2c
--- /dev/null
+++ b/util/perl/OpenSSL/OID.pm
@@ -0,0 +1,365 @@
+# Copyright 2016-2019 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
+
+# Author note: this is originally RL::ASN1::OID,
+# repurposed by the author for OpenSSL use.
+
+package OpenSSL::OID;
+
+use 5.10.0;
+use strict;
+use warnings;
+use Carp;
+
+use Exporter;
+use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
+ at ISA = qw(Exporter);
+ at EXPORT = qw(parse_oid encode_oid register_oid
+ registered_oid_arcs registered_oid_leaves);
+ at EXPORT_OK = qw(encode_oid_nums);
+
+use List::Util;
+
+=head1 NAME
+
+OpenSSL::OID - an OBJECT IDENTIFIER parser / encoder
+
+=head1 VERSION
+
+Version 0.1
+
+=cut
+
+our $VERSION = '0.1';
+
+
+=head1 SYNOPSIS
+
+ use OpenSSL::OID;
+
+ # This gives the array ( 1 2 840 113549 1 1 )
+ my @nums = parse_oid('{ pkcs-1 1 }');
+
+ # This gives the array of DER encoded bytes for the OID, i.e.
+ # ( 42, 134, 72, 134, 247, 13, 1, 1 )
+ my @bytes = encode_oid('{ pkcs-1 1 }');
+
+ # This registers a name with an OID. It's saved internally and
+ # serves as repository of names for further parsing, such as 'pkcs-1'
+ # in the strings used above.
+ register_object('pkcs-1', '{ pkcs 1 }');
+
+
+ use OpenSSL::OID qw(:DEFAULT encode_oid_nums);
+
+ # This does the same as encode_oid(), but takes the output of
+ # parse_oid() as input.
+ my @bytes = encode_oid_nums(@nums);
+
+=head1 EXPORT
+
+The functions parse_oid and encode_oid are exported by default.
+The function encode_oid_nums() can be exported explicitly.
+
+=cut
+
+######## REGEXPS
+
+# ASN.1 object identifiers come in two forms: 1) the bracketed form
+#(referred to as ObjectIdentifierValue in X.690), 2) the dotted form
+#(referred to as XMLObjIdentifierValue in X.690)
+#
+# examples of 1 (these are all the OID for rsaEncrypted):
+#
+# { iso (1) 2 840 11349 1 1 }
+# { pkcs 1 1 }
+# { pkcs1 1 }
+#
+# examples of 2:
+#
+# 1.2.840.113549.1.1
+# pkcs.1.1
+# pkcs1.1
+#
+my $identifier_re = qr/[a-z](?:[-_A-Za-z0-9]*[A-Za-z0-9])?/;
+# The only difference between $objcomponent_re and $xmlobjcomponent_re is
+# the separator in the top branch. Each component is always parsed in two
+# groups, so we get a pair of values regardless. That's the reason for the
+# empty parentheses.
+# Because perl doesn't try to do an exhaustive try of every branch it rather
+# stops on the first that matches, we need to have them in order of longest
+# to shortest where there may be ambiguity.
+my $objcomponent_re = qr/(?|
+ (${identifier_re}) \s* \((\d+)\)
+ |
+ (${identifier_re}) ()
+ |
+ ()(\d+)
+ )/x;
+my $xmlobjcomponent_re = qr/(?|
+ (${identifier_re}) \. \((\d+)\)
+ |
+ (${identifier_re}) ()
+ |
+ () (\d+)
+ )/x;
+
+my $obj_re =
+ qr/(?: \{ \s* (?: ${objcomponent_re} \s+ )* ${objcomponent_re} \s* \} )/x;
+my $xmlobj_re =
+ qr/(?: (?: ${xmlobjcomponent_re} \. )* ${xmlobjcomponent_re} )/x;
+
+######## NAME TO OID REPOSITORY
+
+# Recorded OIDs, to support things like '{ pkcs1 1 }'
+# Do note that we don't currently support relative OIDs
+#
+# The key is the identifier.
+#
+# The value is a hash, composed of:
+# type => 'arc' | 'leaf'
+# nums => [ LIST ]
+# Note that the |type| always starts as a 'leaf', and may change to an 'arc'
+# on the fly, as new OIDs are parsed.
+my %name2oid = ();
+
+########
+
+=head1 SUBROUTINES/METHODS
+
+=over 4
+
+=item parse_oid()
+
+TBA
+
+=cut
+
+sub parse_oid {
+ my $input = shift;
+
+ croak "Invalid extra arguments" if (@_);
+
+ # The components become a list of ( identifier, number ) pairs,
+ # where they can also be the empty string if they are not present
+ # in the input.
+ my @components;
+ if ($input =~ m/^\s*(${obj_re})\s*$/x) {
+ my $oid = $1;
+ @components = ( $oid =~ m/${objcomponent_re}\s*/g );
+ } elsif ($input =~ m/^\s*(${xmlobj_re})\s*$/) {
+ my $oid = $1;
+ @components = ( $oid =~ m/${xmlobjcomponent_re}\.?/g );
+ }
+
+ croak "Invalid ASN.1 object '$input'" unless @components;
+ die "Internal error when parsing '$input'"
+ unless scalar(@components) % 2 == 0;
+
+ # As we currently only support a name without number as first
+ # component, the easiest is to have a direct look at it and
+ # hack it.
+ my @first = List::Util::pairmap {
+ return $b if $b ne '';
+ return @{$name2oid{$a}->{nums}} if $a ne '' && defined $name2oid{$a};
+ croak "Undefined identifier $a" if $a ne '';
+ croak "Empty OID element (how's that possible?)";
+ } ( @components[0..1] );
+
+ my @numbers =
+ (
+ @first,
+ List::Util::pairmap {
+ return $b if $b ne '';
+ croak "Unsupported relative OID $a" if $a ne '';
+ croak "Empty OID element (how's that possible?)";
+ } @components[2..$#components]
+ );
+
+ # If the first component has an identifier and there are other
+ # components following it, we change the type of that identifier
+ # to 'arc'.
+ if (scalar @components > 2
+ && $components[0] ne ''
+ && defined $name2oid{$components[0]}) {
+ $name2oid{$components[0]}->{type} = 'arc';
+ }
+
+ return @numbers;
+}
+
+=item encode_oid()
+
+=cut
+
+# Forward declaration
+sub encode_oid_nums;
+sub encode_oid {
+ return encode_oid_nums parse_oid @_;
+}
+
+=item register_oid()
+
+=cut
+
+sub register_oid {
+ my $name = shift;
+ my @nums = parse_oid @_;
+
+ if (defined $name2oid{$name}) {
+ my $str1 = join(',', @nums);
+ my $str2 = join(',', @{$name2oid{$name}->{nums}});
+
+ croak "Invalid redefinition of $name with different value"
+ unless $str1 eq $str2;
+ } else {
+ $name2oid{$name} = { type => 'leaf', nums => [ @nums ] };
+ }
+}
+
+=item registered_oid_arcs()
+
+=item registered_oid_leaves()
+
+=cut
+
+sub _registered_oids {
+ my $type = shift;
+
+ return grep { $name2oid{$_}->{type} eq $type } keys %name2oid;
+}
+
+sub registered_oid_arcs {
+ return _registered_oids( 'arc' );
+}
+
+sub registered_oid_leaves {
+ return _registered_oids( 'leaf' );
+}
+
+=item encode_oid_nums()
+
+=cut
+
+# Internal helper. It takes a numeric OID component and generates the
+# DER encoding for it.
+sub _gen_oid_bytes {
+ my $num = shift;
+ my $cnt = 0;
+
+ return ( $num ) if $num < 128;
+ return ( ( map { $_ | 0x80 } _gen_oid_bytes($num >> 7) ), $num & 0x7f );
+}
+
+sub encode_oid_nums {
+ my @numbers = @_;
+
+ croak 'Invalid OID values: ( ', join(', ', @numbers), ' )'
+ if (scalar @numbers < 2
+ || $numbers[0] < 0 || $numbers[0] > 2
+ || $numbers[1] < 0 || $numbers[1] > 39);
+
+ my $first = shift(@numbers) * 40 + shift(@numbers);
+ @numbers = ( $first, map { _gen_oid_bytes($_) } @numbers );
+
+ return @numbers;
+}
+
+=back
+
+=head1 AUTHOR
+
+Richard levitte, C<< <richard at levitte.org> >>
+
+=cut
+
+######## UNIT TESTING
+
+use Test::More;
+
+sub TEST {
+ # Order is important, so we make it a pairwise list
+ my @predefined =
+ (
+ 'pkcs' => '1.2.840.113549',
+ 'pkcs-1' => 'pkcs.1',
+ );
+
+ my %good_cases =
+ (
+ ' 1.2.840.113549.1.1 ' => [ 42, 134, 72, 134, 247, 13, 1, 1 ],
+ 'pkcs.1.1' => [ 42, 134, 72, 134, 247, 13, 1, 1 ],
+ 'pkcs-1.1' => [ 42, 134, 72, 134, 247, 13, 1, 1 ],
+ ' { iso (1) 2 840 113549 1 1 } ' => [ 42, 134, 72, 134, 247, 13, 1, 1 ],
+ '{ pkcs 1 1 } ' => [ 42, 134, 72, 134, 247, 13, 1, 1 ],
+ '{pkcs-1 1 }' => [ 42, 134, 72, 134, 247, 13, 1, 1 ],
+ );
+ my @bad_cases =
+ (
+ ' { 1.2.840.113549.1.1 } ',
+ );
+
+ plan tests =>
+ scalar ( @predefined ) / 2
+ + scalar ( keys %good_cases )
+ + scalar @bad_cases;
+
+ note 'Predefine a few names OIDs';
+ foreach my $pair ( List::Util::pairs @predefined ) {
+ ok( defined eval { register_oid(@$pair) },
+ "Registering $pair->[0] => $pair->[1]" );
+ }
+
+ note 'Good cases';
+ foreach ( keys %good_cases ) {
+ subtest "Checking '$_'" => sub {
+ my $oid = shift;
+
+ plan tests => 5;
+
+ my (@l, @e);
+
+ ok( scalar (@l = eval { parse_oid $oid }) > 0,
+ "Parsing" );
+ diag $@ unless @l;
+ ok( scalar (@e = eval { encode_oid_nums @l }) > 0,
+ "Encoding via encode_oid_nums()" );
+ diag $@ unless @e;
+ is_deeply(\@e, $good_cases{$oid}, "Checking encoding");
+ note "'$oid' => ", join(', ', @e) if @e;
+
+ ok( scalar (@e = eval { encode_oid $oid }) > 0,
+ "Encoding directly" );
+ diag $@ unless @e;
+ is_deeply(\@e, $good_cases{$oid}, "Checking encoding");
+ note "'$oid' => ", join(', ', @e) if @e;
+ },
+ $_;
+ }
+
+ note 'Bad cases';
+ foreach ( @bad_cases ) {
+ subtest "Checking '$_'" => sub {
+ my $oid = shift;
+
+ plan tests => 2;
+
+ my (@l, @e);
+
+ ok( scalar (@l = eval { parse_oid $oid }) == 0,
+ "Parsing '$oid'" );
+ note $@ unless @l;
+ ok( scalar (@e = eval { encode_oid_nums @l }) == 0,
+ "Encoding '$oid'" );
+ note $@ unless @e;
+ note "'$oid' => ", join(', ', @e) if @e;
+ },
+ $_;
+ }
+}
+
+1; # End of OpenSSL::OID
More information about the openssl-commits
mailing list