summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2017-10-12 14:10:08 +0200
committerJohannes Berg <johannes.berg@intel.com>2017-10-13 10:57:59 +0200
commit988e2af4b7a0c1bc70188674cfde2bf8b2838bd7 (patch)
tree6cc10692587c0a92cb02d89e19573723051808f0
parentf82274f97829d7f9e11a9793546ba88b084e1199 (diff)
backports: add signature verification code
Uh, this was awful. Because the crypto/ things are completely impossible to backport, I've actually implemented this by using mbedtls and embedding the relevant functions it has... The mbedtls code is taken from mbedtls version 2.6.0 and only minimally modified (mostly to remove <string.h> and similar). Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--backport/backport-include/keys/asymmetric-type.h33
-rw-r--r--backport/backport-include/keys/system_keyring.h10
-rw-r--r--backport/backport-include/linux/key.h66
-rw-r--r--backport/backport-include/linux/verification.h28
-rw-r--r--backport/compat/.gitignore1
-rw-r--r--backport/compat/Kconfig26
-rw-r--r--backport/compat/Makefile29
-rw-r--r--backport/compat/verification/asn1parse.c393
-rw-r--r--backport/compat/verification/bignum.c2447
-rw-r--r--backport/compat/verification/key.c171
-rw-r--r--backport/compat/verification/mbedtls/asn1.h344
-rw-r--r--backport/compat/verification/mbedtls/bignum.h760
-rw-r--r--backport/compat/verification/mbedtls/bn_mul.h887
-rw-r--r--backport/compat/verification/mbedtls/config.h15
-rw-r--r--backport/compat/verification/mbedtls/md.h356
-rw-r--r--backport/compat/verification/mbedtls/md_internal.h116
-rw-r--r--backport/compat/verification/mbedtls/oid.h572
-rw-r--r--backport/compat/verification/mbedtls/pk.h618
-rw-r--r--backport/compat/verification/mbedtls/platform.h12
-rw-r--r--backport/compat/verification/mbedtls/rsa.h672
-rw-r--r--backport/compat/verification/mbedtls/sha1.h135
-rw-r--r--backport/compat/verification/mbedtls/sha256.h140
-rw-r--r--backport/compat/verification/md.c471
-rw-r--r--backport/compat/verification/md_wrap.c577
-rw-r--r--backport/compat/verification/oid.c709
-rw-r--r--backport/compat/verification/pkcs7-asn1.c355
-rw-r--r--backport/compat/verification/pkcs7-asn1.h27
-rw-r--r--backport/compat/verification/public_key.c131
-rw-r--r--backport/compat/verification/rsa.c1872
-rw-r--r--backport/compat/verification/rsapubkey-asn1.c38
-rw-r--r--backport/compat/verification/rsapubkey-asn1.h15
-rw-r--r--backport/compat/verification/sha256.c458
-rw-r--r--backport/compat/verification/verify.c65
-rw-r--r--backport/compat/verification/x509-asn1.c182
-rw-r--r--backport/compat/verification/x509-asn1.h22
-rw-r--r--backport/compat/verification/x509_akid-asn1.c144
-rw-r--r--backport/compat/verification/x509_akid-asn1.h15
-rw-r--r--copy-list13
-rw-r--r--patches/verify.patch86
39 files changed, 13011 insertions, 0 deletions
diff --git a/backport/backport-include/keys/asymmetric-type.h b/backport/backport-include/keys/asymmetric-type.h
new file mode 100644
index 00000000..ee9c4186
--- /dev/null
+++ b/backport/backport-include/keys/asymmetric-type.h
@@ -0,0 +1,33 @@
+#ifndef __BP_ASYMMETRIC_TYPE_H
+#define __BP_ASYMMETRIC_TYPE_H
+#ifdef CPTCFG_BPAUTO_BUILD_SYSTEM_DATA_VERIFICATION
+
+struct asymmetric_key_id {
+ unsigned short len;
+ unsigned char data[];
+};
+
+struct asymmetric_key_ids {
+ struct asymmetric_key_id *id[2];
+};
+
+static inline bool asymmetric_key_id_same(const struct asymmetric_key_id *kid1,
+ const struct asymmetric_key_id *kid2)
+{
+ if (!kid1 || !kid2)
+ return false;
+ if (kid1->len != kid2->len)
+ return false;
+ return memcmp(kid1->data, kid2->data, kid1->len) == 0;
+}
+
+extern struct asymmetric_key_id *
+asymmetric_key_generate_id(const void *val_1, size_t len_1,
+ const void *val_2, size_t len_2);
+
+extern struct key *find_asymmetric_key(struct key *keyring,
+ const struct asymmetric_key_id *id_0,
+ const struct asymmetric_key_id *id_1,
+ bool partial);
+#endif
+#endif /* __BP_ASYMMETRIC_TYPE_H */
diff --git a/backport/backport-include/keys/system_keyring.h b/backport/backport-include/keys/system_keyring.h
new file mode 100644
index 00000000..00d2bfff
--- /dev/null
+++ b/backport/backport-include/keys/system_keyring.h
@@ -0,0 +1,10 @@
+#ifndef __BP_SYSTEM_KEYRING_H
+#define __BP_SYSTEM_KEYRING_H
+#ifndef CPTCFG_BPAUTO_BUILD_SYSTEM_DATA_VERIFICATION
+#include_next <keys/system_keyring.h>
+#else
+#include <linux/key.h>
+
+#define is_hash_blacklisted(...) 0
+#endif /* CPTCFG_BPAUTO_BUILD_SYSTEM_DATA_VERIFICATION */
+#endif /* __BP_SYSTEM_KEYRING_H */
diff --git a/backport/backport-include/linux/key.h b/backport/backport-include/linux/key.h
new file mode 100644
index 00000000..e7abbf47
--- /dev/null
+++ b/backport/backport-include/linux/key.h
@@ -0,0 +1,66 @@
+#ifndef __BP_KEY_H
+#define __BP_KEY_H
+#ifndef CPTCFG_BPAUTO_BUILD_SYSTEM_DATA_VERIFICATION
+#include_next <linux/key.h>
+#else
+#include <linux/types.h>
+#include <linux/refcount.h>
+#include <linux/list.h>
+#include <keys/asymmetric-type.h>
+
+typedef uint32_t key_perm_t;
+
+struct key {
+ refcount_t refcount;
+ const char *description;
+ s32 serial;
+ struct list_head list;
+
+ struct asymmetric_key_ids kids;
+ struct public_key *public_key;
+ struct public_key_signature *sig;
+
+ bool keyring;
+};
+
+typedef struct __key_reference_with_attributes *key_ref_t;
+
+static inline key_ref_t make_key_ref(const struct key *key,
+ bool possession)
+{
+ return (key_ref_t) ((unsigned long) key | possession);
+}
+
+static inline struct key *key_ref_to_ptr(const key_ref_t key_ref)
+{
+ return (struct key *) ((unsigned long) key_ref & ~1UL);
+}
+
+#define key_put LINUX_BACKPORT(key_put)
+extern void key_put(struct key *key);
+
+static inline void key_ref_put(key_ref_t key_ref)
+{
+ key_put(key_ref_to_ptr(key_ref));
+}
+
+#define key_create_or_update(keyring, type, desc, payload, plen, perm, flags) \
+ bp_key_create_or_update(keyring, desc, payload, plen)
+
+extern key_ref_t bp_key_create_or_update(key_ref_t keyring,
+ const char *description,
+ const void *payload,
+ size_t plen);
+
+#define keyring_alloc(desc, uid, gid, cred, perm, flags, restrict, dest) \
+ bp_keyring_alloc();
+
+extern struct key *bp_keyring_alloc(void);
+
+static inline s32 key_serial(const struct key *key)
+{
+ return key ? key->serial : 0;
+}
+
+#endif /* CPTCFG_BPAUTO_BUILD_SYSTEM_DATA_VERIFICATION */
+#endif /* __BP_KEY_H */
diff --git a/backport/backport-include/linux/verification.h b/backport/backport-include/linux/verification.h
new file mode 100644
index 00000000..10e1bcfb
--- /dev/null
+++ b/backport/backport-include/linux/verification.h
@@ -0,0 +1,28 @@
+#ifndef __BP_VERIFICATION_H
+#define __BP_VERIFICATION_H
+#include <linux/version.h>
+#ifndef CPTCFG_BPAUTO_BUILD_SYSTEM_DATA_VERIFICATION
+#include_next <linux/verification.h>
+#else
+#include <linux/key.h>
+
+enum key_being_used_for {
+ VERIFYING_MODULE_SIGNATURE,
+ VERIFYING_FIRMWARE_SIGNATURE,
+ VERIFYING_KEXEC_PE_SIGNATURE,
+ VERIFYING_KEY_SIGNATURE,
+ VERIFYING_KEY_SELF_SIGNATURE,
+ VERIFYING_UNSPECIFIED_SIGNATURE,
+ NR__KEY_BEING_USED_FOR
+};
+
+extern int verify_pkcs7_signature(const void *data, size_t len,
+ const void *raw_pkcs7, size_t pkcs7_len,
+ struct key *trusted_keys,
+ enum key_being_used_for usage,
+ int (*view_content)(void *ctx,
+ const void *data, size_t len,
+ size_t asn1hdrlen),
+ void *ctx);
+#endif /* LINUX_VERSION_IS_GEQ(4,7,0) */
+#endif /* __BP_VERIFICATION_H */
diff --git a/backport/compat/.gitignore b/backport/compat/.gitignore
new file mode 100644
index 00000000..72ff0e99
--- /dev/null
+++ b/backport/compat/.gitignore
@@ -0,0 +1 @@
+oid_registry_data.c
diff --git a/backport/compat/Kconfig b/backport/compat/Kconfig
index b1666710..542cf0cc 100644
--- a/backport/compat/Kconfig
+++ b/backport/compat/Kconfig
@@ -174,3 +174,29 @@ config BPAUTO_REFCOUNT
depends on KERNEL_4_11
#h-file linux/refcount.h
#c-file lib/refcount.c
+
+config BPAUTO_SYSTEM_DATA_VERIFICATION
+ bool
+
+config BPAUTO_BUILD_SYSTEM_DATA_VERIFICATION
+ bool
+ default y if BPAUTO_SYSTEM_DATA_VERIFICATION
+ depends on KERNEL_4_7 || !SYSTEM_DATA_VERIFICATION
+ select BPAUTO_ASN1_DECODER
+ select BPAUTO_PUBLIC_KEY
+ select BPAUTO_PKCS7
+ #h-file linux/oid_registry.h
+ #c-file lib/oid_registry.c
+
+config BPAUTO_PUBLIC_KEY
+ bool
+ #h-file crypto/public_key.h
+
+config BPAUTO_ASN1_DECODER
+ bool
+ #h-file linux/asn1_decoder.h
+ #c-file lib/asn1_decoder.c
+
+config BPAUTO_PKCS7
+ bool
+ #h-file crypto/pkcs7.h
diff --git a/backport/compat/Makefile b/backport/compat/Makefile
index 1658f588..ead22a00 100644
--- a/backport/compat/Makefile
+++ b/backport/compat/Makefile
@@ -39,3 +39,32 @@ compat-$(CPTCFG_KERNEL_4_10) += backport-4.10.o
compat-$(CPTCFG_BPAUTO_BUILD_CRYPTO_CCM) += crypto-ccm.o
compat-$(CPTCFG_BPAUTO_CRYPTO_SKCIPHER) += crypto-skcipher.o
+
+compat-$(CPTCFG_BPAUTO_BUILD_SYSTEM_DATA_VERIFICATION) += verification/verify.o
+compat-$(CPTCFG_BPAUTO_BUILD_SYSTEM_DATA_VERIFICATION) += verification/pkcs7-asn1.o
+compat-$(CPTCFG_BPAUTO_BUILD_SYSTEM_DATA_VERIFICATION) += verification/pkcs7_verify.o
+compat-$(CPTCFG_BPAUTO_BUILD_SYSTEM_DATA_VERIFICATION) += verification/pkcs7_parser.o
+compat-$(CPTCFG_BPAUTO_BUILD_SYSTEM_DATA_VERIFICATION) += verification/x509-asn1.o
+compat-$(CPTCFG_BPAUTO_BUILD_SYSTEM_DATA_VERIFICATION) += verification/x509_akid-asn1.o
+compat-$(CPTCFG_BPAUTO_BUILD_SYSTEM_DATA_VERIFICATION) += verification/x509_cert_parser.o
+compat-$(CPTCFG_BPAUTO_BUILD_SYSTEM_DATA_VERIFICATION) += verification/x509_public_key.o
+compat-$(CPTCFG_BPAUTO_BUILD_SYSTEM_DATA_VERIFICATION) += verification/pkcs7_trust.o
+compat-$(CPTCFG_BPAUTO_BUILD_SYSTEM_DATA_VERIFICATION) += verification/key.o
+compat-$(CPTCFG_BPAUTO_BUILD_SYSTEM_DATA_VERIFICATION) += verification/public_key.o
+compat-$(CPTCFG_BPAUTO_BUILD_SYSTEM_DATA_VERIFICATION) += verification/rsa.o
+compat-$(CPTCFG_BPAUTO_BUILD_SYSTEM_DATA_VERIFICATION) += verification/bignum.o
+compat-$(CPTCFG_BPAUTO_BUILD_SYSTEM_DATA_VERIFICATION) += verification/md.o
+compat-$(CPTCFG_BPAUTO_BUILD_SYSTEM_DATA_VERIFICATION) += verification/md_wrap.o
+compat-$(CPTCFG_BPAUTO_BUILD_SYSTEM_DATA_VERIFICATION) += verification/sha256.o
+compat-$(CPTCFG_BPAUTO_BUILD_SYSTEM_DATA_VERIFICATION) += verification/oid.o
+compat-$(CPTCFG_BPAUTO_BUILD_SYSTEM_DATA_VERIFICATION) += verification/asn1parse.o
+compat-$(CPTCFG_BPAUTO_BUILD_SYSTEM_DATA_VERIFICATION) += verification/rsapubkey-asn1.o
+
+$(obj)/lib-oid_registry.o: $(obj)/oid_registry_data.c
+
+$(obj)/oid_registry_data.c: $(src)/../include/linux/backport-oid_registry.h \
+ $(src)/build_OID_registry
+ $(call cmd,build_OID_registry)
+
+quiet_cmd_build_OID_registry = GEN $@
+ cmd_build_OID_registry = perl $(src)/build_OID_registry $< $@
diff --git a/backport/compat/verification/asn1parse.c b/backport/compat/verification/asn1parse.c
new file mode 100644
index 00000000..e81713c7
--- /dev/null
+++ b/backport/compat/verification/asn1parse.c
@@ -0,0 +1,393 @@
+/*
+ * Generic ASN.1 parsing
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: GPL-2.0
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * This file is part of mbed TLS (https://tls.mbed.org)
+ */
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "mbedtls/config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#if defined(MBEDTLS_ASN1_PARSE_C)
+
+#include "mbedtls/asn1.h"
+
+#if defined(MBEDTLS_BIGNUM_C)
+#include "mbedtls/bignum.h"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_C)
+#include "mbedtls/platform.h"
+#else
+#include <stdlib.h>
+#define mbedtls_calloc calloc
+#define mbedtls_free free
+#endif
+
+/* Implementation that should never be optimized out by the compiler */
+static void mbedtls_zeroize( void *v, size_t n ) {
+ volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0;
+}
+
+/*
+ * ASN.1 DER decoding routines
+ */
+int mbedtls_asn1_get_len( unsigned char **p,
+ const unsigned char *end,
+ size_t *len )
+{
+ if( ( end - *p ) < 1 )
+ return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
+
+ if( ( **p & 0x80 ) == 0 )
+ *len = *(*p)++;
+ else
+ {
+ switch( **p & 0x7F )
+ {
+ case 1:
+ if( ( end - *p ) < 2 )
+ return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
+
+ *len = (*p)[1];
+ (*p) += 2;
+ break;
+
+ case 2:
+ if( ( end - *p ) < 3 )
+ return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
+
+ *len = ( (size_t)(*p)[1] << 8 ) | (*p)[2];
+ (*p) += 3;
+ break;
+
+ case 3:
+ if( ( end - *p ) < 4 )
+ return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
+
+ *len = ( (size_t)(*p)[1] << 16 ) |
+ ( (size_t)(*p)[2] << 8 ) | (*p)[3];
+ (*p) += 4;
+ break;
+
+ case 4:
+ if( ( end - *p ) < 5 )
+ return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
+
+ *len = ( (size_t)(*p)[1] << 24 ) | ( (size_t)(*p)[2] << 16 ) |
+ ( (size_t)(*p)[3] << 8 ) | (*p)[4];
+ (*p) += 5;
+ break;
+
+ default:
+ return( MBEDTLS_ERR_ASN1_INVALID_LENGTH );
+ }
+ }
+
+ if( *len > (size_t) ( end - *p ) )
+ return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
+
+ return( 0 );
+}
+
+int mbedtls_asn1_get_tag( unsigned char **p,
+ const unsigned char *end,
+ size_t *len, int tag )
+{
+ if( ( end - *p ) < 1 )
+ return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
+
+ if( **p != tag )
+ return( MBEDTLS_ERR_ASN1_UNEXPECTED_TAG );
+
+ (*p)++;
+
+ return( mbedtls_asn1_get_len( p, end, len ) );
+}
+
+int mbedtls_asn1_get_bool( unsigned char **p,
+ const unsigned char *end,
+ int *val )
+{
+ int ret;
+ size_t len;
+
+ if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_BOOLEAN ) ) != 0 )
+ return( ret );
+
+ if( len != 1 )
+ return( MBEDTLS_ERR_ASN1_INVALID_LENGTH );
+
+ *val = ( **p != 0 ) ? 1 : 0;
+ (*p)++;
+
+ return( 0 );
+}
+
+int mbedtls_asn1_get_int( unsigned char **p,
+ const unsigned char *end,
+ int *val )
+{
+ int ret;
+ size_t len;
+
+ if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_INTEGER ) ) != 0 )
+ return( ret );
+
+ if( len == 0 || len > sizeof( int ) || ( **p & 0x80 ) != 0 )
+ return( MBEDTLS_ERR_ASN1_INVALID_LENGTH );
+
+ *val = 0;
+
+ while( len-- > 0 )
+ {
+ *val = ( *val << 8 ) | **p;
+ (*p)++;
+ }
+
+ return( 0 );
+}
+
+#if defined(MBEDTLS_BIGNUM_C)
+int mbedtls_asn1_get_mpi( unsigned char **p,
+ const unsigned char *end,
+ mbedtls_mpi *X )
+{
+ int ret;
+ size_t len;
+
+ if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_INTEGER ) ) != 0 )
+ return( ret );
+
+ ret = mbedtls_mpi_read_binary( X, *p, len );
+
+ *p += len;
+
+ return( ret );
+}
+#endif /* MBEDTLS_BIGNUM_C */
+
+int mbedtls_asn1_get_bitstring( unsigned char **p, const unsigned char *end,
+ mbedtls_asn1_bitstring *bs)
+{
+ int ret;
+
+ /* Certificate type is a single byte bitstring */
+ if( ( ret = mbedtls_asn1_get_tag( p, end, &bs->len, MBEDTLS_ASN1_BIT_STRING ) ) != 0 )
+ return( ret );
+
+ /* Check length, subtract one for actual bit string length */
+ if( bs->len < 1 )
+ return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
+ bs->len -= 1;
+
+ /* Get number of unused bits, ensure unused bits <= 7 */
+ bs->unused_bits = **p;
+ if( bs->unused_bits > 7 )
+ return( MBEDTLS_ERR_ASN1_INVALID_LENGTH );
+ (*p)++;
+
+ /* Get actual bitstring */
+ bs->p = *p;
+ *p += bs->len;
+
+ if( *p != end )
+ return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
+
+ return( 0 );
+}
+
+/*
+ * Get a bit string without unused bits
+ */
+int mbedtls_asn1_get_bitstring_null( unsigned char **p, const unsigned char *end,
+ size_t *len )
+{
+ int ret;
+
+ if( ( ret = mbedtls_asn1_get_tag( p, end, len, MBEDTLS_ASN1_BIT_STRING ) ) != 0 )
+ return( ret );
+
+ if( (*len)-- < 2 || *(*p)++ != 0 )
+ return( MBEDTLS_ERR_ASN1_INVALID_DATA );
+
+ return( 0 );
+}
+
+
+
+/*
+ * Parses and splits an ASN.1 "SEQUENCE OF <tag>"
+ */
+int mbedtls_asn1_get_sequence_of( unsigned char **p,
+ const unsigned char *end,
+ mbedtls_asn1_sequence *cur,
+ int tag)
+{
+ int ret;
+ size_t len;
+ mbedtls_asn1_buf *buf;
+
+ /* Get main sequence tag */
+ if( ( ret = mbedtls_asn1_get_tag( p, end, &len,
+ MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
+ return( ret );
+
+ if( *p + len != end )
+ return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
+
+ while( *p < end )
+ {
+ buf = &(cur->buf);
+ buf->tag = **p;
+
+ if( ( ret = mbedtls_asn1_get_tag( p, end, &buf->len, tag ) ) != 0 )
+ return( ret );
+
+ buf->p = *p;
+ *p += buf->len;
+
+ /* Allocate and assign next pointer */
+ if( *p < end )
+ {
+ cur->next = (mbedtls_asn1_sequence*)mbedtls_calloc( 1,
+ sizeof( mbedtls_asn1_sequence ) );
+
+ if( cur->next == NULL )
+ return( MBEDTLS_ERR_ASN1_ALLOC_FAILED );
+
+ cur = cur->next;
+ }
+ }
+
+ /* Set final sequence entry's next pointer to NULL */
+ cur->next = NULL;
+
+ if( *p != end )
+ return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
+
+ return( 0 );
+}
+
+int mbedtls_asn1_get_alg( unsigned char **p,
+ const unsigned char *end,
+ mbedtls_asn1_buf *alg, mbedtls_asn1_buf *params )
+{
+ int ret;
+ size_t len;
+
+ if( ( ret = mbedtls_asn1_get_tag( p, end, &len,
+ MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
+ return( ret );
+
+ if( ( end - *p ) < 1 )
+ return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
+
+ alg->tag = **p;
+ end = *p + len;
+
+ if( ( ret = mbedtls_asn1_get_tag( p, end, &alg->len, MBEDTLS_ASN1_OID ) ) != 0 )
+ return( ret );
+
+ alg->p = *p;
+ *p += alg->len;
+
+ if( *p == end )
+ {
+ mbedtls_zeroize( params, sizeof(mbedtls_asn1_buf) );
+ return( 0 );
+ }
+
+ params->tag = **p;
+ (*p)++;
+
+ if( ( ret = mbedtls_asn1_get_len( p, end, &params->len ) ) != 0 )
+ return( ret );
+
+ params->p = *p;
+ *p += params->len;
+
+ if( *p != end )
+ return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
+
+ return( 0 );
+}
+
+int mbedtls_asn1_get_alg_null( unsigned char **p,
+ const unsigned char *end,
+ mbedtls_asn1_buf *alg )
+{
+ int ret;
+ mbedtls_asn1_buf params;
+
+ memset( &params, 0, sizeof(mbedtls_asn1_buf) );
+
+ if( ( ret = mbedtls_asn1_get_alg( p, end, alg, &params ) ) != 0 )
+ return( ret );
+
+ if( ( params.tag != MBEDTLS_ASN1_NULL && params.tag != 0 ) || params.len != 0 )
+ return( MBEDTLS_ERR_ASN1_INVALID_DATA );
+
+ return( 0 );
+}
+
+void mbedtls_asn1_free_named_data( mbedtls_asn1_named_data *cur )
+{
+ if( cur == NULL )
+ return;
+
+ mbedtls_free( cur->oid.p );
+ mbedtls_free( cur->val.p );
+
+ mbedtls_zeroize( cur, sizeof( mbedtls_asn1_named_data ) );
+}
+
+void mbedtls_asn1_free_named_data_list( mbedtls_asn1_named_data **head )
+{
+ mbedtls_asn1_named_data *cur;
+
+ while( ( cur = *head ) != NULL )
+ {
+ *head = cur->next;
+ mbedtls_asn1_free_named_data( cur );
+ mbedtls_free( cur );
+ }
+}
+
+mbedtls_asn1_named_data *mbedtls_asn1_find_named_data( mbedtls_asn1_named_data *list,
+ const char *oid, size_t len )
+{
+ while( list != NULL )
+ {
+ if( list->oid.len == len &&
+ memcmp( list->oid.p, oid, len ) == 0 )
+ {
+ break;
+ }
+
+ list = list->next;
+ }
+
+ return( list );
+}
+
+#endif /* MBEDTLS_ASN1_PARSE_C */
diff --git a/backport/compat/verification/bignum.c b/backport/compat/verification/bignum.c
new file mode 100644
index 00000000..7edfb083
--- /dev/null
+++ b/backport/compat/verification/bignum.c
@@ -0,0 +1,2447 @@
+/*
+ * Multi-precision integer library
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: GPL-2.0
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * This file is part of mbed TLS (https://tls.mbed.org)
+ */
+
+/*
+ * The following sources were referenced in the design of this Multi-precision
+ * Integer library:
+ *
+ * [1] Handbook of Applied Cryptography - 1997
+ * Menezes, van Oorschot and Vanstone
+ *
+ * [2] Multi-Precision Math
+ * Tom St Denis
+ * https://github.com/libtom/libtommath/blob/develop/tommath.pdf
+ *
+ * [3] GNU Multi-Precision Arithmetic Library
+ * https://gmplib.org/manual/index.html
+ *
+ */
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "mbedtls/config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#if defined(MBEDTLS_BIGNUM_C)
+
+#include "mbedtls/bignum.h"
+#include "mbedtls/bn_mul.h"
+
+#if defined(MBEDTLS_PLATFORM_C)
+#include "mbedtls/platform.h"
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#define mbedtls_printf printf
+#define mbedtls_calloc calloc
+#define mbedtls_free free
+#endif
+
+/* Implementation that should never be optimized out by the compiler */
+static void mbedtls_mpi_zeroize( mbedtls_mpi_uint *v, size_t n ) {
+ volatile mbedtls_mpi_uint *p = v; while( n-- ) *p++ = 0;
+}
+
+#define ciL (sizeof(mbedtls_mpi_uint)) /* chars in limb */
+#define biL (ciL << 3) /* bits in limb */
+#define biH (ciL << 2) /* half limb size */
+
+#define MPI_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */
+
+/*
+ * Convert between bits/chars and number of limbs
+ * Divide first in order to avoid potential overflows
+ */
+#define BITS_TO_LIMBS(i) ( (i) / biL + ( (i) % biL != 0 ) )
+#define CHARS_TO_LIMBS(i) ( (i) / ciL + ( (i) % ciL != 0 ) )
+
+/*
+ * Initialize one MPI
+ */
+void mbedtls_mpi_init( mbedtls_mpi *X )
+{
+ if( X == NULL )
+ return;
+
+ X->s = 1;
+ X->n = 0;
+ X->p = NULL;
+}
+
+/*
+ * Unallocate one MPI
+ */
+void mbedtls_mpi_free( mbedtls_mpi *X )
+{
+ if( X == NULL )
+ return;
+
+ if( X->p != NULL )
+ {
+ mbedtls_mpi_zeroize( X->p, X->n );
+ mbedtls_free( X->p );
+ }
+
+ X->s = 1;
+ X->n = 0;
+ X->p = NULL;
+}
+
+/*
+ * Enlarge to the specified number of limbs
+ */
+int mbedtls_mpi_grow( mbedtls_mpi *X, size_t nblimbs )
+{
+ mbedtls_mpi_uint *p;
+
+ if( nblimbs > MBEDTLS_MPI_MAX_LIMBS )
+ return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
+
+ if( X->n < nblimbs )
+ {
+ if( ( p = (mbedtls_mpi_uint*)mbedtls_calloc( nblimbs, ciL ) ) == NULL )
+ return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
+
+ if( X->p != NULL )
+ {
+ memcpy( p, X->p, X->n * ciL );
+ mbedtls_mpi_zeroize( X->p, X->n );
+ mbedtls_free( X->p );
+ }
+
+ X->n = nblimbs;
+ X->p = p;
+ }
+
+ return( 0 );
+}
+
+/*
+ * Resize down as much as possible,
+ * while keeping at least the specified number of limbs
+ */
+int mbedtls_mpi_shrink( mbedtls_mpi *X, size_t nblimbs )
+{
+ mbedtls_mpi_uint *p;
+ size_t i;
+
+ /* Actually resize up in this case */
+ if( X->n <= nblimbs )
+ return( mbedtls_mpi_grow( X, nblimbs ) );
+
+ for( i = X->n - 1; i > 0; i-- )
+ if( X->p[i] != 0 )
+ break;
+ i++;
+
+ if( i < nblimbs )
+ i = nblimbs;
+
+ if( ( p = (mbedtls_mpi_uint*)mbedtls_calloc( i, ciL ) ) == NULL )
+ return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
+
+ if( X->p != NULL )
+ {
+ memcpy( p, X->p, i * ciL );
+ mbedtls_mpi_zeroize( X->p, X->n );
+ mbedtls_free( X->p );
+ }
+
+ X->n = i;
+ X->p = p;
+
+ return( 0 );
+}
+
+/*
+ * Copy the contents of Y into X
+ */
+int mbedtls_mpi_copy( mbedtls_mpi *X, const mbedtls_mpi *Y )
+{
+ int ret;
+ size_t i;
+
+ if( X == Y )
+ return( 0 );
+
+ if( Y->p == NULL )
+ {
+ mbedtls_mpi_free( X );
+ return( 0 );
+ }
+
+ for( i = Y->n - 1; i > 0; i-- )
+ if( Y->p[i] != 0 )
+ break;
+ i++;
+
+ X->s = Y->s;
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i ) );
+
+ memset( X->p, 0, X->n * ciL );
+ memcpy( X->p, Y->p, i * ciL );
+
+cleanup:
+
+ return( ret );
+}
+
+/*
+ * Swap the contents of X and Y
+ */
+void mbedtls_mpi_swap( mbedtls_mpi *X, mbedtls_mpi *Y )
+{
+ mbedtls_mpi T;
+
+ memcpy( &T, X, sizeof( mbedtls_mpi ) );
+ memcpy( X, Y, sizeof( mbedtls_mpi ) );
+ memcpy( Y, &T, sizeof( mbedtls_mpi ) );
+}
+
+/*
+ * Conditionally assign X = Y, without leaking information
+ * about whether the assignment was made or not.
+ * (Leaking information about the respective sizes of X and Y is ok however.)
+ */
+int mbedtls_mpi_safe_cond_assign( mbedtls_mpi *X, const mbedtls_mpi *Y, unsigned char assign )
+{
+ int ret = 0;
+ size_t i;
+
+ /* make sure assign is 0 or 1 in a time-constant manner */
+ assign = (assign | (unsigned char)-assign) >> 7;
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, Y->n ) );
+
+ X->s = X->s * ( 1 - assign ) + Y->s * assign;
+
+ for( i = 0; i < Y->n; i++ )
+ X->p[i] = X->p[i] * ( 1 - assign ) + Y->p[i] * assign;
+
+ for( ; i < X->n; i++ )
+ X->p[i] *= ( 1 - assign );
+
+cleanup:
+ return( ret );
+}
+
+/*
+ * Conditionally swap X and Y, without leaking information
+ * about whether the swap was made or not.
+ * Here it is not ok to simply swap the pointers, which whould lead to
+ * different memory access patterns when X and Y are used afterwards.
+ */
+int mbedtls_mpi_safe_cond_swap( mbedtls_mpi *X, mbedtls_mpi *Y, unsigned char swap )
+{
+ int ret, s;
+ size_t i;
+ mbedtls_mpi_uint tmp;
+
+ if( X == Y )
+ return( 0 );
+
+ /* make sure swap is 0 or 1 in a time-constant manner */
+ swap = (swap | (unsigned char)-swap) >> 7;
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, Y->n ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_grow( Y, X->n ) );
+
+ s = X->s;
+ X->s = X->s * ( 1 - swap ) + Y->s * swap;
+ Y->s = Y->s * ( 1 - swap ) + s * swap;
+
+
+ for( i = 0; i < X->n; i++ )
+ {
+ tmp = X->p[i];
+ X->p[i] = X->p[i] * ( 1 - swap ) + Y->p[i] * swap;
+ Y->p[i] = Y->p[i] * ( 1 - swap ) + tmp * swap;
+ }
+
+cleanup:
+ return( ret );
+}
+
+/*
+ * Set value from integer
+ */
+int mbedtls_mpi_lset( mbedtls_mpi *X, mbedtls_mpi_sint z )
+{
+ int ret;
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, 1 ) );
+ memset( X->p, 0, X->n * ciL );
+
+ X->p[0] = ( z < 0 ) ? -z : z;
+ X->s = ( z < 0 ) ? -1 : 1;
+
+cleanup:
+
+ return( ret );
+}
+
+/*
+ * Get a specific bit
+ */
+int mbedtls_mpi_get_bit( const mbedtls_mpi *X, size_t pos )
+{
+ if( X->n * biL <= pos )
+ return( 0 );
+
+ return( ( X->p[pos / biL] >> ( pos % biL ) ) & 0x01 );
+}
+
+/*
+ * Set a bit to a specific value of 0 or 1
+ */
+int mbedtls_mpi_set_bit( mbedtls_mpi *X, size_t pos, unsigned char val )
+{
+ int ret = 0;
+ size_t off = pos / biL;
+ size_t idx = pos % biL;
+
+ if( val != 0 && val != 1 )
+ return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
+
+ if( X->n * biL <= pos )
+ {
+ if( val == 0 )
+ return( 0 );
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, off + 1 ) );
+ }
+
+ X->p[off] &= ~( (mbedtls_mpi_uint) 0x01 << idx );
+ X->p[off] |= (mbedtls_mpi_uint) val << idx;
+
+cleanup:
+
+ return( ret );
+}
+
+/*
+ * Return the number of less significant zero-bits
+ */
+size_t mbedtls_mpi_lsb( const mbedtls_mpi *X )
+{
+ size_t i, j, count = 0;
+
+ for( i = 0; i < X->n; i++ )
+ for( j = 0; j < biL; j++, count++ )
+ if( ( ( X->p[i] >> j ) & 1 ) != 0 )
+ return( count );
+
+ return( 0 );
+}
+
+/*
+ * Count leading zero bits in a given integer
+ */
+static size_t mbedtls_clz( const mbedtls_mpi_uint x )
+{
+ size_t j;
+ mbedtls_mpi_uint mask = (mbedtls_mpi_uint) 1 << (biL - 1);
+
+ for( j = 0; j < biL; j++ )
+ {
+ if( x & mask ) break;
+
+ mask >>= 1;
+ }
+
+ return j;
+}
+
+/*
+ * Return the number of bits
+ */
+size_t mbedtls_mpi_bitlen( const mbedtls_mpi *X )
+{
+ size_t i, j;
+
+ if( X->n == 0 )
+ return( 0 );
+
+ for( i = X->n - 1; i > 0; i-- )
+ if( X->p[i] != 0 )
+ break;
+
+ j = biL - mbedtls_clz( X->p[i] );
+
+ return( ( i * biL ) + j );
+}
+
+/*
+ * Return the total size in bytes
+ */
+size_t mbedtls_mpi_size( const mbedtls_mpi *X )
+{
+ return( ( mbedtls_mpi_bitlen( X ) + 7 ) >> 3 );
+}
+
+/*
+ * Convert an ASCII character to digit value
+ */
+static int mpi_get_digit( mbedtls_mpi_uint *d, int radix, char c )
+{
+ *d = 255;
+
+ if( c >= 0x30 && c <= 0x39 ) *d = c - 0x30;
+ if( c >= 0x41 && c <= 0x46 ) *d = c - 0x37;
+ if( c >= 0x61 && c <= 0x66 ) *d = c - 0x57;
+
+ if( *d >= (mbedtls_mpi_uint) radix )
+ return( MBEDTLS_ERR_MPI_INVALID_CHARACTER );
+
+ return( 0 );
+}
+
+/*
+ * Import from an ASCII string
+ */
+int mbedtls_mpi_read_string( mbedtls_mpi *X, int radix, const char *s )
+{
+ int ret;
+ size_t i, j, slen, n;
+ mbedtls_mpi_uint d;
+ mbedtls_mpi T;
+
+ if( radix < 2 || radix > 16 )
+ return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
+
+ mbedtls_mpi_init( &T );
+
+ slen = strlen( s );
+
+ if( radix == 16 )
+ {
+ if( slen > MPI_SIZE_T_MAX >> 2 )
+ return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
+
+ n = BITS_TO_LIMBS( slen << 2 );
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, n ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) );
+
+ for( i = slen, j = 0; i > 0; i--, j++ )
+ {
+ if( i == 1 && s[i - 1] == '-' )
+ {
+ X->s = -1;
+ break;
+ }
+
+ MBEDTLS_MPI_CHK( mpi_get_digit( &d, radix, s[i - 1] ) );
+ X->p[j / ( 2 * ciL )] |= d << ( ( j % ( 2 * ciL ) ) << 2 );
+ }
+ }
+ else
+ {
+ MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) );
+
+ for( i = 0; i < slen; i++ )
+ {
+ if( i == 0 && s[i] == '-' )
+ {
+ X->s = -1;
+ continue;
+ }
+
+ MBEDTLS_MPI_CHK( mpi_get_digit( &d, radix, s[i] ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T, X, radix ) );
+
+ if( X->s == 1 )
+ {
+ MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, &T, d ) );
+ }
+ else
+ {
+ MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( X, &T, d ) );
+ }
+ }
+ }
+
+cleanup:
+
+ mbedtls_mpi_free( &T );
+
+ return( ret );
+}
+
+/*
+ * Helper to write the digits high-order first
+ */
+static int mpi_write_hlp( mbedtls_mpi *X, int radix, char **p )
+{
+ int ret;
+ mbedtls_mpi_uint r;
+
+ if( radix < 2 || radix > 16 )
+ return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, radix ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_div_int( X, NULL, X, radix ) );
+
+ if( mbedtls_mpi_cmp_int( X, 0 ) != 0 )
+ MBEDTLS_MPI_CHK( mpi_write_hlp( X, radix, p ) );
+
+ if( r < 10 )
+ *(*p)++ = (char)( r + 0x30 );
+ else
+ *(*p)++ = (char)( r + 0x37 );
+
+cleanup:
+
+ return( ret );
+}
+
+/*
+ * Export into an ASCII string
+ */
+int mbedtls_mpi_write_string( const mbedtls_mpi *X, int radix,
+ char *buf, size_t buflen, size_t *olen )
+{
+ int ret = 0;
+ size_t n;
+ char *p;
+ mbedtls_mpi T;
+
+ if( radix < 2 || radix > 16 )
+ return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
+
+ n = mbedtls_mpi_bitlen( X );
+ if( radix >= 4 ) n >>= 1;
+ if( radix >= 16 ) n >>= 1;
+ /*
+ * Round up the buffer length to an even value to ensure that there is
+ * enough room for hexadecimal values that can be represented in an odd
+ * number of digits.
+ */
+ n += 3 + ( ( n + 1 ) & 1 );
+
+ if( buflen < n )
+ {
+ *olen = n;
+ return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL );
+ }
+
+ p = buf;
+ mbedtls_mpi_init( &T );
+
+ if( X->s == -1 )
+ *p++ = '-';
+
+ if( radix == 16 )
+ {
+ int c;
+ size_t i, j, k;
+
+ for( i = X->n, k = 0; i > 0; i-- )
+ {
+ for( j = ciL; j > 0; j-- )
+ {
+ c = ( X->p[i - 1] >> ( ( j - 1 ) << 3) ) & 0xFF;
+
+ if( c == 0 && k == 0 && ( i + j ) != 2 )
+ continue;
+
+ *(p++) = "0123456789ABCDEF" [c / 16];
+ *(p++) = "0123456789ABCDEF" [c % 16];
+ k = 1;
+ }
+ }
+ }
+ else
+ {
+ MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &T, X ) );
+
+ if( T.s == -1 )
+ T.s = 1;
+
+ MBEDTLS_MPI_CHK( mpi_write_hlp( &T, radix, &p ) );
+ }
+
+ *p++ = '\0';
+ *olen = p - buf;
+
+cleanup:
+
+ mbedtls_mpi_free( &T );
+
+ return( ret );
+}
+
+#if defined(MBEDTLS_FS_IO)
+/*
+ * Read X from an opened file
+ */
+int mbedtls_mpi_read_file( mbedtls_mpi *X, int radix, FILE *fin )
+{
+ mbedtls_mpi_uint d;
+ size_t slen;
+ char *p;
+ /*
+ * Buffer should have space for (short) label and decimal formatted MPI,
+ * newline characters and '\0'
+ */
+ char s[ MBEDTLS_MPI_RW_BUFFER_SIZE ];
+
+ memset( s, 0, sizeof( s ) );
+ if( fgets( s, sizeof( s ) - 1, fin ) == NULL )
+ return( MBEDTLS_ERR_MPI_FILE_IO_ERROR );
+
+ slen = strlen( s );
+ if( slen == sizeof( s ) - 2 )
+ return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL );
+
+ if( slen > 0 && s[slen - 1] == '\n' ) { slen--; s[slen] = '\0'; }
+ if( slen > 0 && s[slen - 1] == '\r' ) { slen--; s[slen] = '\0'; }
+
+ p = s + slen;
+ while( p-- > s )
+ if( mpi_get_digit( &d, radix, *p ) != 0 )
+ break;
+
+ return( mbedtls_mpi_read_string( X, radix, p + 1 ) );
+}
+
+/*
+ * Write X into an opened file (or stdout if fout == NULL)
+ */
+int mbedtls_mpi_write_file( const char *p, const mbedtls_mpi *X, int radix, FILE *fout )
+{
+ int ret;
+ size_t n, slen, plen;
+ /*
+ * Buffer should have space for (short) label and decimal formatted MPI,
+ * newline characters and '\0'
+ */
+ char s[ MBEDTLS_MPI_RW_BUFFER_SIZE ];
+
+ memset( s, 0, sizeof( s ) );
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_write_string( X, radix, s, sizeof( s ) - 2, &n ) );
+
+ if( p == NULL ) p = "";
+
+ plen = strlen( p );
+ slen = strlen( s );
+ s[slen++] = '\r';
+ s[slen++] = '\n';
+
+ if( fout != NULL )
+ {
+ if( fwrite( p, 1, plen, fout ) != plen ||
+ fwrite( s, 1, slen, fout ) != slen )
+ return( MBEDTLS_ERR_MPI_FILE_IO_ERROR );
+ }
+ else
+ mbedtls_printf( "%s%s", p, s );
+
+cleanup:
+
+ return( ret );
+}
+#endif /* MBEDTLS_FS_IO */
+
+/*
+ * Import X from unsigned binary data, big endian
+ */
+int mbedtls_mpi_read_binary( mbedtls_mpi *X, const unsigned char *buf, size_t buflen )
+{
+ int ret;
+ size_t i, j, n;
+
+ for( n = 0; n < buflen; n++ )
+ if( buf[n] != 0 )
+ break;
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, CHARS_TO_LIMBS( buflen - n ) ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) );
+
+ for( i = buflen, j = 0; i > n; i--, j++ )
+ X->p[j / ciL] |= ((mbedtls_mpi_uint) buf[i - 1]) << ((j % ciL) << 3);
+
+cleanup:
+
+ return( ret );
+}
+
+/*
+ * Export X into unsigned binary data, big endian
+ */
+int mbedtls_mpi_write_binary( const mbedtls_mpi *X, unsigned char *buf, size_t buflen )
+{
+ size_t i, j, n;
+
+ n = mbedtls_mpi_size( X );
+
+ if( buflen < n )
+ return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL );
+
+ memset( buf, 0, buflen );
+
+ for( i = buflen - 1, j = 0; n > 0; i--, j++, n-- )
+ buf[i] = (unsigned char)( X->p[j / ciL] >> ((j % ciL) << 3) );
+
+ return( 0 );
+}
+
+/*
+ * Left-shift: X <<= count
+ */
+int mbedtls_mpi_shift_l( mbedtls_mpi *X, size_t count )
+{
+ int ret;
+ size_t i, v0, t1;
+ mbedtls_mpi_uint r0 = 0, r1;
+
+ v0 = count / (biL );
+ t1 = count & (biL - 1);
+
+ i = mbedtls_mpi_bitlen( X ) + count;
+
+ if( X->n * biL < i )
+ MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, BITS_TO_LIMBS( i ) ) );
+
+ ret = 0;
+
+ /*
+ * shift by count / limb_size
+ */
+ if( v0 > 0 )
+ {
+ for( i = X->n; i > v0; i-- )
+ X->p[i - 1] = X->p[i - v0 - 1];
+
+ for( ; i > 0; i-- )
+ X->p[i - 1] = 0;
+ }
+
+ /*
+ * shift by count % limb_size
+ */
+ if( t1 > 0 )
+ {
+ for( i = v0; i < X->n; i++ )
+ {
+ r1 = X->p[i] >> (biL - t1);
+ X->p[i] <<= t1;
+ X->p[i] |= r0;
+ r0 = r1;
+ }
+ }
+
+cleanup:
+
+ return( ret );
+}
+
+/*
+ * Right-shift: X >>= count
+ */
+int mbedtls_mpi_shift_r( mbedtls_mpi *X, size_t count )
+{
+ size_t i, v0, v1;
+ mbedtls_mpi_uint r0 = 0, r1;
+
+ v0 = count / biL;
+ v1 = count & (biL - 1);
+
+ if( v0 > X->n || ( v0 == X->n && v1 > 0 ) )
+ return mbedtls_mpi_lset( X, 0 );
+
+ /*
+ * shift by count / limb_size
+ */
+ if( v0 > 0 )
+ {
+ for( i = 0; i < X->n - v0; i++ )
+ X->p[i] = X->p[i + v0];
+
+ for( ; i < X->n; i++ )
+ X->p[i] = 0;
+ }
+
+ /*
+ * shift by count % limb_size
+ */
+ if( v1 > 0 )
+ {
+ for( i = X->n; i > 0; i-- )
+ {
+ r1 = X->p[i - 1] << (biL - v1);
+ X->p[i - 1] >>= v1;
+ X->p[i - 1] |= r0;
+ r0 = r1;
+ }
+ }
+
+ return( 0 );
+}
+
+/*
+ * Compare unsigned values
+ */
+int mbedtls_mpi_cmp_abs( const mbedtls_mpi *X, const mbedtls_mpi *Y )
+{
+ size_t i, j;
+
+ for( i = X->n; i > 0; i-- )
+ if( X->p[i - 1] != 0 )
+ break;
+
+ for( j = Y->n; j > 0; j-- )
+ if( Y->p[j - 1] != 0 )
+ break;
+
+ if( i == 0 && j == 0 )
+ return( 0 );
+
+ if( i > j ) return( 1 );
+ if( j > i ) return( -1 );
+
+ for( ; i > 0; i-- )
+ {
+ if( X->p[i - 1] > Y->p[i - 1] ) return( 1 );
+ if( X->p[i - 1] < Y->p[i - 1] ) return( -1 );
+ }
+
+ return( 0 );
+}
+
+/*
+ * Compare signed values
+ */
+int mbedtls_mpi_cmp_mpi( const mbedtls_mpi *X, const mbedtls_mpi *Y )
+{
+ size_t i, j;
+
+ for( i = X->n; i > 0; i-- )
+ if( X->p[i - 1] != 0 )
+ break;
+
+ for( j = Y->n; j > 0; j-- )
+ if( Y->p[j - 1] != 0 )
+ break;
+
+ if( i == 0 && j == 0 )
+ return( 0 );
+
+ if( i > j ) return( X->s );
+ if( j > i ) return( -Y->s );
+
+ if( X->s > 0 && Y->s < 0 ) return( 1 );
+ if( Y->s > 0 && X->s < 0 ) return( -1 );
+
+ for( ; i > 0; i-- )
+ {
+ if( X->p[i - 1] > Y->p[i - 1] ) return( X->s );
+ if( X->p[i - 1] < Y->p[i - 1] ) return( -X->s );
+ }
+
+ return( 0 );
+}
+
+/*
+ * Compare signed values
+ */
+int mbedtls_mpi_cmp_int( const mbedtls_mpi *X, mbedtls_mpi_sint z )
+{
+ mbedtls_mpi Y;
+ mbedtls_mpi_uint p[1];
+
+ *p = ( z < 0 ) ? -z : z;
+ Y.s = ( z < 0 ) ? -1 : 1;
+ Y.n = 1;
+ Y.p = p;
+
+ return( mbedtls_mpi_cmp_mpi( X, &Y ) );
+}
+
+/*
+ * Unsigned addition: X = |A| + |B| (HAC 14.7)
+ */
+int mbedtls_mpi_add_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
+{
+ int ret;
+ size_t i, j;
+ mbedtls_mpi_uint *o, *p, c, tmp;
+
+ if( X == B )
+ {
+ const mbedtls_mpi *T = A; A = X; B = T;
+ }
+
+ if( X != A )
+ MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, A ) );
+
+ /*
+ * X should always be positive as a result of unsigned additions.
+ */
+ X->s = 1;
+
+ for( j = B->n; j > 0; j-- )
+ if( B->p[j - 1] != 0 )
+ break;
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, j ) );
+
+ o = B->p; p = X->p; c = 0;
+
+ /*
+ * tmp is used because it might happen that p == o
+ */
+ for( i = 0; i < j; i++, o++, p++ )
+ {
+ tmp= *o;
+ *p += c; c = ( *p < c );
+ *p += tmp; c += ( *p < tmp );
+ }
+
+ while( c != 0 )
+ {
+ if( i >= X->n )
+ {
+ MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i + 1 ) );
+ p = X->p + i;
+ }
+
+ *p += c; c = ( *p < c ); i++; p++;
+ }
+
+cleanup:
+
+ return( ret );
+}
+
+/*
+ * Helper for mbedtls_mpi subtraction
+ */
+static void mpi_sub_hlp( size_t n, mbedtls_mpi_uint *s, mbedtls_mpi_uint *d )
+{
+ size_t i;
+ mbedtls_mpi_uint c, z;
+
+ for( i = c = 0; i < n; i++, s++, d++ )
+ {
+ z = ( *d < c ); *d -= c;
+ c = ( *d < *s ) + z; *d -= *s;
+ }
+
+ while( c != 0 )
+ {
+ z = ( *d < c ); *d -= c;
+ c = z; i++; d++;
+ }
+}
+
+/*
+ * Unsigned subtraction: X = |A| - |B| (HAC 14.9)
+ */
+int mbedtls_mpi_sub_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
+{
+ mbedtls_mpi TB;
+ int ret;
+ size_t n;
+
+ if( mbedtls_mpi_cmp_abs( A, B ) < 0 )
+ return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE );
+
+ mbedtls_mpi_init( &TB );
+
+ if( X == B )
+ {
+ MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, B ) );
+ B = &TB;
+ }
+
+ if( X != A )
+ MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, A ) );
+
+ /*
+ * X should always be positive as a result of unsigned subtractions.
+ */
+ X->s = 1;
+
+ ret = 0;
+
+ for( n = B->n; n > 0; n-- )
+ if( B->p[n - 1] != 0 )
+ break;
+
+ mpi_sub_hlp( n, B->p, X->p );
+
+cleanup:
+
+ mbedtls_mpi_free( &TB );
+
+ return( ret );
+}
+
+/*
+ * Signed addition: X = A + B
+ */
+int mbedtls_mpi_add_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
+{
+ int ret, s = A->s;
+
+ if( A->s * B->s < 0 )
+ {
+ if( mbedtls_mpi_cmp_abs( A, B ) >= 0 )
+ {
+ MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, A, B ) );
+ X->s = s;
+ }
+ else
+ {
+ MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, B, A ) );
+ X->s = -s;
+ }
+ }
+ else
+ {
+ MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( X, A, B ) );
+ X->s = s;
+ }
+
+cleanup:
+
+ return( ret );
+}
+
+/*
+ * Signed subtraction: X = A - B
+ */
+int mbedtls_mpi_sub_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
+{
+ int ret, s = A->s;
+
+ if( A->s * B->s > 0 )
+ {
+ if( mbedtls_mpi_cmp_abs( A, B ) >= 0 )
+ {
+ MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, A, B ) );
+ X->s = s;
+ }
+ else
+ {
+ MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, B, A ) );
+ X->s = -s;
+ }
+ }
+ else
+ {
+ MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( X, A, B ) );
+ X->s = s;
+ }
+
+cleanup:
+
+ return( ret );
+}
+
+/*
+ * Signed addition: X = A + b
+ */
+int mbedtls_mpi_add_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b )
+{
+ mbedtls_mpi _B;
+ mbedtls_mpi_uint p[1];
+
+ p[0] = ( b < 0 ) ? -b : b;
+ _B.s = ( b < 0 ) ? -1 : 1;
+ _B.n = 1;
+ _B.p = p;
+
+ return( mbedtls_mpi_add_mpi( X, A, &_B ) );
+}
+
+/*
+ * Signed subtraction: X = A - b
+ */
+int mbedtls_mpi_sub_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b )
+{
+ mbedtls_mpi _B;
+ mbedtls_mpi_uint p[1];
+
+ p[0] = ( b < 0 ) ? -b : b;
+ _B.s = ( b < 0 ) ? -1 : 1;
+ _B.n = 1;
+ _B.p = p;
+
+ return( mbedtls_mpi_sub_mpi( X, A, &_B ) );
+}
+
+/*
+ * Helper for mbedtls_mpi multiplication
+ */
+static
+#if defined(__APPLE__) && defined(__arm__)
+/*
+ * Apple LLVM version 4.2 (clang-425.0.24) (based on LLVM 3.2svn)
+ * appears to need this to prevent bad ARM code generation at -O3.
+ */
+__attribute__ ((noinline))
+#endif
+void mpi_mul_hlp( size_t i, mbedtls_mpi_uint *s, mbedtls_mpi_uint *d, mbedtls_mpi_uint b )
+{
+ mbedtls_mpi_uint c = 0, t = 0;
+
+#if defined(MULADDC_HUIT)
+ for( ; i >= 8; i -= 8 )
+ {
+ MULADDC_INIT
+ MULADDC_HUIT
+ MULADDC_STOP
+ }
+
+ for( ; i > 0; i-- )
+ {
+ MULADDC_INIT
+ MULADDC_CORE
+ MULADDC_STOP
+ }
+#else /* MULADDC_HUIT */
+ for( ; i >= 16; i -= 16 )
+ {
+ MULADDC_INIT
+ MULADDC_CORE MULADDC_CORE
+ MULADDC_CORE MULADDC_CORE
+ MULADDC_CORE MULADDC_CORE
+ MULADDC_CORE MULADDC_CORE
+
+ MULADDC_CORE MULADDC_CORE
+ MULADDC_CORE MULADDC_CORE
+ MULADDC_CORE MULADDC_CORE
+ MULADDC_CORE MULADDC_CORE
+ MULADDC_STOP
+ }
+
+ for( ; i >= 8; i -= 8 )
+ {
+ MULADDC_INIT
+ MULADDC_CORE MULADDC_CORE
+ MULADDC_CORE MULADDC_CORE
+
+ MULADDC_CORE MULADDC_CORE
+ MULADDC_CORE MULADDC_CORE
+ MULADDC_STOP
+ }
+
+ for( ; i > 0; i-- )
+ {
+ MULADDC_INIT
+ MULADDC_CORE
+ MULADDC_STOP
+ }
+#endif /* MULADDC_HUIT */
+
+ t++;
+
+ do {
+ *d += c; c = ( *d < c ); d++;
+ }
+ while( c != 0 );
+}
+
+/*
+ * Baseline multiplication: X = A * B (HAC 14.12)
+ */
+int mbedtls_mpi_mul_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
+{
+ int ret;
+ size_t i, j;
+ mbedtls_mpi TA, TB;
+
+ mbedtls_mpi_init( &TA ); mbedtls_mpi_init( &TB );
+
+ if( X == A ) { MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TA, A ) ); A = &TA; }
+ if( X == B ) { MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, B ) ); B = &TB; }
+
+ for( i = A->n; i > 0; i-- )
+ if( A->p[i - 1] != 0 )
+ break;
+
+ for( j = B->n; j > 0; j-- )
+ if( B->p[j - 1] != 0 )
+ break;
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i + j ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) );
+
+ for( i++; j > 0; j-- )
+ mpi_mul_hlp( i - 1, A->p, X->p + j - 1, B->p[j - 1] );
+
+ X->s = A->s * B->s;
+
+cleanup:
+
+ mbedtls_mpi_free( &TB ); mbedtls_mpi_free( &TA );
+
+ return( ret );
+}
+
+/*
+ * Baseline multiplication: X = A * b
+ */
+int mbedtls_mpi_mul_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_uint b )
+{
+ mbedtls_mpi _B;
+ mbedtls_mpi_uint p[1];
+
+ _B.s = 1;
+ _B.n = 1;
+ _B.p = p;
+ p[0] = b;
+
+ return( mbedtls_mpi_mul_mpi( X, A, &_B ) );
+}
+
+/*
+ * Unsigned integer divide - double mbedtls_mpi_uint dividend, u1/u0, and
+ * mbedtls_mpi_uint divisor, d
+ */
+static mbedtls_mpi_uint mbedtls_int_div_int( mbedtls_mpi_uint u1,
+ mbedtls_mpi_uint u0, mbedtls_mpi_uint d, mbedtls_mpi_uint *r )
+{
+#if defined(MBEDTLS_HAVE_UDBL)
+ mbedtls_t_udbl dividend, quotient;
+#else
+ const mbedtls_mpi_uint radix = (mbedtls_mpi_uint) 1 << biH;
+ const mbedtls_mpi_uint uint_halfword_mask = ( (mbedtls_mpi_uint) 1 << biH ) - 1;
+ mbedtls_mpi_uint d0, d1, q0, q1, rAX, r0, quotient;
+ mbedtls_mpi_uint u0_msw, u0_lsw;
+ size_t s;
+#endif
+
+ /*
+ * Check for overflow
+ */
+ if( 0 == d || u1 >= d )
+ {
+ if (r != NULL) *r = ~0;
+
+ return ( ~0 );
+ }
+
+#if defined(MBEDTLS_HAVE_UDBL)
+ dividend = (mbedtls_t_udbl) u1 << biL;
+ dividend |= (mbedtls_t_udbl) u0;
+ quotient = dividend / d;
+ if( quotient > ( (mbedtls_t_udbl) 1 << biL ) - 1 )
+ quotient = ( (mbedtls_t_udbl) 1 << biL ) - 1;
+
+ if( r != NULL )
+ *r = (mbedtls_mpi_uint)( dividend - (quotient * d ) );
+
+ return (mbedtls_mpi_uint) quotient;
+#else
+
+ /*
+ * Algorithm D, Section 4.3.1 - The Art of Computer Programming
+ * Vol. 2 - Seminumerical Algorithms, Knuth
+ */
+
+ /*
+ * Normalize the divisor, d, and dividend, u0, u1
+ */
+ s = mbedtls_clz( d );
+ d = d << s;
+
+ u1 = u1 << s;
+ u1 |= ( u0 >> ( biL - s ) ) & ( -(mbedtls_mpi_sint)s >> ( biL - 1 ) );
+ u0 = u0 << s;
+
+ d1 = d >> biH;
+ d0 = d & uint_halfword_mask;
+
+ u0_msw = u0 >> biH;
+ u0_lsw = u0 & uint_halfword_mask;
+
+ /*
+ * Find the first quotient and remainder
+ */
+ q1 = u1 / d1;
+ r0 = u1 - d1 * q1;
+
+ while( q1 >= radix || ( q1 * d0 > radix * r0 + u0_msw ) )
+ {
+ q1 -= 1;
+ r0 += d1;
+
+ if ( r0 >= radix ) break;
+ }
+
+ rAX = ( u1 * radix ) + ( u0_msw - q1 * d );
+ q0 = rAX / d1;
+ r0 = rAX - q0 * d1;
+
+ while( q0 >= radix || ( q0 * d0 > radix * r0 + u0_lsw ) )
+ {
+ q0 -= 1;
+ r0 += d1;
+
+ if ( r0 >= radix ) break;
+ }
+
+ if (r != NULL)
+ *r = ( rAX * radix + u0_lsw - q0 * d ) >> s;
+
+ quotient = q1 * radix + q0;
+
+ return quotient;
+#endif
+}
+
+/*
+ * Division by mbedtls_mpi: A = Q * B + R (HAC 14.20)
+ */
+int mbedtls_mpi_div_mpi( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B )
+{
+ int ret;
+ size_t i, n, t, k;
+ mbedtls_mpi X, Y, Z, T1, T2;
+
+ if( mbedtls_mpi_cmp_int( B, 0 ) == 0 )
+ return( MBEDTLS_ERR_MPI_DIVISION_BY_ZERO );
+
+ mbedtls_mpi_init( &X ); mbedtls_mpi_init( &Y ); mbedtls_mpi_init( &Z );
+ mbedtls_mpi_init( &T1 ); mbedtls_mpi_init( &T2 );
+
+ if( mbedtls_mpi_cmp_abs( A, B ) < 0 )
+ {
+ if( Q != NULL ) MBEDTLS_MPI_CHK( mbedtls_mpi_lset( Q, 0 ) );
+ if( R != NULL ) MBEDTLS_MPI_CHK( mbedtls_mpi_copy( R, A ) );
+ return( 0 );
+ }
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &X, A ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Y, B ) );
+ X.s = Y.s = 1;
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &Z, A->n + 2 ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &Z, 0 ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &T1, 2 ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &T2, 3 ) );
+
+ k = mbedtls_mpi_bitlen( &Y ) % biL;
+ if( k < biL - 1 )
+ {
+ k = biL - 1 - k;
+ MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &X, k ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &Y, k ) );
+ }
+ else k = 0;
+
+ n = X.n - 1;
+ t = Y.n - 1;
+ MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &Y, biL * ( n - t ) ) );
+
+ while( mbedtls_mpi_cmp_mpi( &X, &Y ) >= 0 )
+ {
+ Z.p[n - t]++;
+ MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &X, &X, &Y ) );
+ }
+ MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &Y, biL * ( n - t ) ) );
+
+ for( i = n; i > t ; i-- )
+ {
+ if( X.p[i] >= Y.p[t] )
+ Z.p[i - t - 1] = ~0;
+ else
+ {
+ Z.p[i - t - 1] = mbedtls_int_div_int( X.p[i], X.p[i - 1],
+ Y.p[t], NULL);
+ }
+
+ Z.p[i - t - 1]++;
+ do
+ {
+ Z.p[i - t - 1]--;
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &T1, 0 ) );
+ T1.p[0] = ( t < 1 ) ? 0 : Y.p[t - 1];
+ T1.p[1] = Y.p[t];
+ MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T1, &T1, Z.p[i - t - 1] ) );
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &T2, 0 ) );
+ T2.p[0] = ( i < 2 ) ? 0 : X.p[i - 2];
+ T2.p[1] = ( i < 1 ) ? 0 : X.p[i - 1];
+ T2.p[2] = X.p[i];
+ }
+ while( mbedtls_mpi_cmp_mpi( &T1, &T2 ) > 0 );
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T1, &Y, Z.p[i - t - 1] ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &T1, biL * ( i - t - 1 ) ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &X, &X, &T1 ) );
+
+ if( mbedtls_mpi_cmp_int( &X, 0 ) < 0 )
+ {
+ MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &T1, &Y ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &T1, biL * ( i - t - 1 ) ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &X, &X, &T1 ) );
+ Z.p[i - t - 1]--;
+ }
+ }
+
+ if( Q != NULL )
+ {
+ MBEDTLS_MPI_CHK( mbedtls_mpi_copy( Q, &Z ) );
+ Q->s = A->s * B->s;
+ }
+
+ if( R != NULL )
+ {
+ MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &X, k ) );
+ X.s = A->s;
+ MBEDTLS_MPI_CHK( mbedtls_mpi_copy( R, &X ) );
+
+ if( mbedtls_mpi_cmp_int( R, 0 ) == 0 )
+ R->s = 1;
+ }
+
+cleanup:
+
+ mbedtls_mpi_free( &X ); mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &Z );
+ mbedtls_mpi_free( &T1 ); mbedtls_mpi_free( &T2 );
+
+ return( ret );
+}
+
+/*
+ * Division by int: A = Q * b + R
+ */
+int mbedtls_mpi_div_int( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, mbedtls_mpi_sint b )
+{
+ mbedtls_mpi _B;
+ mbedtls_mpi_uint p[1];
+
+ p[0] = ( b < 0 ) ? -b : b;
+ _B.s = ( b < 0 ) ? -1 : 1;
+ _B.n = 1;
+ _B.p = p;
+
+ return( mbedtls_mpi_div_mpi( Q, R, A, &_B ) );
+}
+
+/*
+ * Modulo: R = A mod B
+ */
+int mbedtls_mpi_mod_mpi( mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B )
+{
+ int ret;
+
+ if( mbedtls_mpi_cmp_int( B, 0 ) < 0 )
+ return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE );
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( NULL, R, A, B ) );
+
+ while( mbedtls_mpi_cmp_int( R, 0 ) < 0 )
+ MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( R, R, B ) );
+
+ while( mbedtls_mpi_cmp_mpi( R, B ) >= 0 )
+ MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( R, R, B ) );
+
+cleanup:
+
+ return( ret );
+}
+
+/*
+ * Modulo: r = A mod b
+ */
+int mbedtls_mpi_mod_int( mbedtls_mpi_uint *r, const mbedtls_mpi *A, mbedtls_mpi_sint b )
+{
+ size_t i;
+ mbedtls_mpi_uint x, y, z;
+
+ if( b == 0 )
+ return( MBEDTLS_ERR_MPI_DIVISION_BY_ZERO );
+
+ if( b < 0 )
+ return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE );
+
+ /*
+ * handle trivial cases
+ */
+ if( b == 1 )
+ {
+ *r = 0;
+ return( 0 );
+ }
+
+ if( b == 2 )
+ {
+ *r = A->p[0] & 1;
+ return( 0 );
+ }
+
+ /*
+ * general case
+ */
+ for( i = A->n, y = 0; i > 0; i-- )
+ {
+ x = A->p[i - 1];
+ y = ( y << biH ) | ( x >> biH );
+ z = y / b;
+ y -= z * b;
+
+ x <<= biH;
+ y = ( y << biH ) | ( x >> biH );
+ z = y / b;
+ y -= z * b;
+ }
+
+ /*
+ * If A is negative, then the current y represents a negative value.
+ * Flipping it to the positive side.
+ */
+ if( A->s < 0 && y != 0 )
+ y = b - y;
+
+ *r = y;
+
+ return( 0 );
+}
+
+/*
+ * Fast Montgomery initialization (thanks to Tom St Denis)
+ */
+static void mpi_montg_init( mbedtls_mpi_uint *mm, const mbedtls_mpi *N )
+{
+ mbedtls_mpi_uint x, m0 = N->p[0];
+ unsigned int i;
+
+ x = m0;
+ x += ( ( m0 + 2 ) & 4 ) << 1;
+
+ for( i = biL; i >= 8; i /= 2 )
+ x *= ( 2 - ( m0 * x ) );
+
+ *mm = ~x + 1;
+}
+
+/*
+ * Montgomery multiplication: A = A * B * R^-1 mod N (HAC 14.36)
+ */
+static int mpi_montmul( mbedtls_mpi *A, const mbedtls_mpi *B, const mbedtls_mpi *N, mbedtls_mpi_uint mm,
+ const mbedtls_mpi *T )
+{
+ size_t i, n, m;
+ mbedtls_mpi_uint u0, u1, *d;
+
+ if( T->n < N->n + 1 || T->p == NULL )
+ return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
+
+ memset( T->p, 0, T->n * ciL );
+
+ d = T->p;
+ n = N->n;
+ m = ( B->n < n ) ? B->n : n;
+
+ for( i = 0; i < n; i++ )
+ {
+ /*
+ * T = (T + u0*B + u1*N) / 2^biL
+ */
+ u0 = A->p[i];
+ u1 = ( d[0] + u0 * B->p[0] ) * mm;
+
+ mpi_mul_hlp( m, B->p, d, u0 );
+ mpi_mul_hlp( n, N->p, d, u1 );
+
+ *d++ = u0; d[n + 1] = 0;
+ }
+
+ memcpy( A->p, d, ( n + 1 ) * ciL );
+
+ if( mbedtls_mpi_cmp_abs( A, N ) >= 0 )
+ mpi_sub_hlp( n, N->p, A->p );
+ else
+ /* prevent timing attacks */
+ mpi_sub_hlp( n, A->p, T->p );
+
+ return( 0 );
+}
+
+/*
+ * Montgomery reduction: A = A * R^-1 mod N
+ */
+static int mpi_montred( mbedtls_mpi *A, const mbedtls_mpi *N, mbedtls_mpi_uint mm, const mbedtls_mpi *T )
+{
+ mbedtls_mpi_uint z = 1;
+ mbedtls_mpi U;
+
+ U.n = U.s = (int) z;
+ U.p = &z;
+
+ return( mpi_montmul( A, &U, N, mm, T ) );
+}
+
+/*
+ * Sliding-window exponentiation: X = A^E mod N (HAC 14.85)
+ */
+int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *E, const mbedtls_mpi *N, mbedtls_mpi *_RR )
+{
+ int ret;
+ size_t wbits, wsize, one = 1;
+ size_t i, j, nblimbs;
+ size_t bufsize, nbits;
+ mbedtls_mpi_uint ei, mm, state;
+ mbedtls_mpi RR, T, W[ 2 << MBEDTLS_MPI_WINDOW_SIZE ], Apos;
+ int neg;
+
+ if( mbedtls_mpi_cmp_int( N, 0 ) < 0 || ( N->p[0] & 1 ) == 0 )
+ return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
+
+ if( mbedtls_mpi_cmp_int( E, 0 ) < 0 )
+ return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
+
+ /*
+ * Init temps and window size
+ */
+ mpi_montg_init( &mm, N );
+ mbedtls_mpi_init( &RR ); mbedtls_mpi_init( &T );
+ mbedtls_mpi_init( &Apos );
+ memset( W, 0, sizeof( W ) );
+
+ i = mbedtls_mpi_bitlen( E );
+
+ wsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 :
+ ( i > 79 ) ? 4 : ( i > 23 ) ? 3 : 1;
+
+ if( wsize > MBEDTLS_MPI_WINDOW_SIZE )
+ wsize = MBEDTLS_MPI_WINDOW_SIZE;
+
+ j = N->n + 1;
+ MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, j ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[1], j ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &T, j * 2 ) );
+
+ /*
+ * Compensate for negative A (and correct at the end)
+ */
+ neg = ( A->s == -1 );
+ if( neg )
+ {
+ MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Apos, A ) );
+ Apos.s = 1;
+ A = &Apos;
+ }
+
+ /*
+ * If 1st call, pre-compute R^2 mod N
+ */
+ if( _RR == NULL || _RR->p == NULL )
+ {
+ MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &RR, 1 ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &RR, N->n * 2 * biL ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &RR, &RR, N ) );
+
+ if( _RR != NULL )
+ memcpy( _RR, &RR, sizeof( mbedtls_mpi ) );
+ }
+ else
+ memcpy( &RR, _RR, sizeof( mbedtls_mpi ) );
+
+ /*
+ * W[1] = A * R^2 * R^-1 mod N = A * R mod N
+ */
+ if( mbedtls_mpi_cmp_mpi( A, N ) >= 0 )
+ MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &W[1], A, N ) );
+ else
+ MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[1], A ) );
+
+ MBEDTLS_MPI_CHK( mpi_montmul( &W[1], &RR, N, mm, &T ) );
+
+ /*
+ * X = R^2 * R^-1 mod N = R mod N
+ */
+ MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, &RR ) );
+ MBEDTLS_MPI_CHK( mpi_montred( X, N, mm, &T ) );
+
+ if( wsize > 1 )
+ {
+ /*
+ * W[1 << (wsize - 1)] = W[1] ^ (wsize - 1)
+ */
+ j = one << ( wsize - 1 );
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[j], N->n + 1 ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[j], &W[1] ) );
+
+ for( i = 0; i < wsize - 1; i++ )
+ MBEDTLS_MPI_CHK( mpi_montmul( &W[j], &W[j], N, mm, &T ) );
+
+ /*
+ * W[i] = W[i - 1] * W[1]
+ */
+ for( i = j + 1; i < ( one << wsize ); i++ )
+ {
+ MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[i], N->n + 1 ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[i], &W[i - 1] ) );
+
+ MBEDTLS_MPI_CHK( mpi_montmul( &W[i], &W[1], N, mm, &T ) );
+ }
+ }
+
+ nblimbs = E->n;
+ bufsize = 0;
+ nbits = 0;
+ wbits = 0;
+ state = 0;
+
+ while( 1 )
+ {
+ if( bufsize == 0 )
+ {
+ if( nblimbs == 0 )
+ break;
+
+ nblimbs--;
+
+ bufsize = sizeof( mbedtls_mpi_uint ) << 3;
+ }
+
+ bufsize--;
+
+ ei = (E->p[nblimbs] >> bufsize) & 1;
+
+ /*
+ * skip leading 0s
+ */
+ if( ei == 0 && state == 0 )
+ continue;
+
+ if( ei == 0 && state == 1 )
+ {
+ /*
+ * out of window, square X
+ */
+ MBEDTLS_MPI_CHK( mpi_montmul( X, X, N, mm, &T ) );
+ continue;
+ }
+
+ /*
+ * add ei to current window
+ */
+ state = 2;
+
+ nbits++;
+ wbits |= ( ei << ( wsize - nbits ) );
+
+ if( nbits == wsize )
+ {
+ /*
+ * X = X^wsize R^-1 mod N
+ */
+ for( i = 0; i < wsize; i++ )
+ MBEDTLS_MPI_CHK( mpi_montmul( X, X, N, mm, &T ) );
+
+ /*
+ * X = X * W[wbits] R^-1 mod N
+ */
+ MBEDTLS_MPI_CHK( mpi_montmul( X, &W[wbits], N, mm, &T ) );
+
+ state--;
+ nbits = 0;
+ wbits = 0;
+ }
+ }
+
+ /*
+ * process the remaining bits
+ */
+ for( i = 0; i < nbits; i++ )
+ {
+ MBEDTLS_MPI_CHK( mpi_montmul( X, X, N, mm, &T ) );
+
+ wbits <<= 1;
+
+ if( ( wbits & ( one << wsize ) ) != 0 )
+ MBEDTLS_MPI_CHK( mpi_montmul( X, &W[1], N, mm, &T ) );
+ }
+
+ /*
+ * X = A^E * R * R^-1 mod N = A^E mod N
+ */
+ MBEDTLS_MPI_CHK( mpi_montred( X, N, mm, &T ) );
+
+ if( neg && E->n != 0 && ( E->p[0] & 1 ) != 0 )
+ {
+ X->s = -1;
+ MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( X, N, X ) );
+ }
+
+cleanup:
+
+ for( i = ( one << ( wsize - 1 ) ); i < ( one << wsize ); i++ )
+ mbedtls_mpi_free( &W[i] );
+
+ mbedtls_mpi_free( &W[1] ); mbedtls_mpi_free( &T ); mbedtls_mpi_free( &Apos );
+
+ if( _RR == NULL || _RR->p == NULL )
+ mbedtls_mpi_free( &RR );
+
+ return( ret );
+}
+
+/*
+ * Greatest common divisor: G = gcd(A, B) (HAC 14.54)
+ */
+int mbedtls_mpi_gcd( mbedtls_mpi *G, const mbedtls_mpi *A, const mbedtls_mpi *B )
+{
+ int ret;
+ size_t lz, lzt;
+ mbedtls_mpi TG, TA, TB;
+
+ mbedtls_mpi_init( &TG ); mbedtls_mpi_init( &TA ); mbedtls_mpi_init( &TB );
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TA, A ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, B ) );
+
+ lz = mbedtls_mpi_lsb( &TA );
+ lzt = mbedtls_mpi_lsb( &TB );
+
+ if( lzt < lz )
+ lz = lzt;
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TA, lz ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TB, lz ) );
+
+ TA.s = TB.s = 1;
+
+ while( mbedtls_mpi_cmp_int( &TA, 0 ) != 0 )
+ {
+ MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TA, mbedtls_mpi_lsb( &TA ) ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TB, mbedtls_mpi_lsb( &TB ) ) );
+
+ if( mbedtls_mpi_cmp_mpi( &TA, &TB ) >= 0 )
+ {
+ MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( &TA, &TA, &TB ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TA, 1 ) );
+ }
+ else
+ {
+ MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( &TB, &TB, &TA ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TB, 1 ) );
+ }
+ }
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &TB, lz ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_copy( G, &TB ) );
+
+cleanup:
+
+ mbedtls_mpi_free( &TG ); mbedtls_mpi_free( &TA ); mbedtls_mpi_free( &TB );
+
+ return( ret );
+}
+
+/*
+ * Fill X with size bytes of random.
+ *
+ * Use a temporary bytes representation to make sure the result is the same
+ * regardless of the platform endianness (useful when f_rng is actually
+ * deterministic, eg for tests).
+ */
+int mbedtls_mpi_fill_random( mbedtls_mpi *X, size_t size,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng )
+{
+ int ret;
+ unsigned char buf[MBEDTLS_MPI_MAX_SIZE];
+
+ if( size > MBEDTLS_MPI_MAX_SIZE )
+ return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
+
+ MBEDTLS_MPI_CHK( f_rng( p_rng, buf, size ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( X, buf, size ) );
+
+cleanup:
+ return( ret );
+}
+
+/*
+ * Modular inverse: X = A^-1 mod N (HAC 14.61 / 14.64)
+ */
+int mbedtls_mpi_inv_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *N )
+{
+ int ret;
+ mbedtls_mpi G, TA, TU, U1, U2, TB, TV, V1, V2;
+
+ if( mbedtls_mpi_cmp_int( N, 1 ) <= 0 )
+ return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
+
+ mbedtls_mpi_init( &TA ); mbedtls_mpi_init( &TU ); mbedtls_mpi_init( &U1 ); mbedtls_mpi_init( &U2 );
+ mbedtls_mpi_init( &G ); mbedtls_mpi_init( &TB ); mbedtls_mpi_init( &TV );
+ mbedtls_mpi_init( &V1 ); mbedtls_mpi_init( &V2 );
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &G, A, N ) );
+
+ if( mbedtls_mpi_cmp_int( &G, 1 ) != 0 )
+ {
+ ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
+ goto cleanup;
+ }
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &TA, A, N ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TU, &TA ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, N ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TV, N ) );
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &U1, 1 ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &U2, 0 ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &V1, 0 ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &V2, 1 ) );
+
+ do
+ {
+ while( ( TU.p[0] & 1 ) == 0 )
+ {
+ MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TU, 1 ) );
+
+ if( ( U1.p[0] & 1 ) != 0 || ( U2.p[0] & 1 ) != 0 )
+ {
+ MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &U1, &U1, &TB ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U2, &U2, &TA ) );
+ }
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &U1, 1 ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &U2, 1 ) );
+ }
+
+ while( ( TV.p[0] & 1 ) == 0 )
+ {
+ MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TV, 1 ) );
+
+ if( ( V1.p[0] & 1 ) != 0 || ( V2.p[0] & 1 ) != 0 )
+ {
+ MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &V1, &V1, &TB ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V2, &V2, &TA ) );
+ }
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &V1, 1 ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &V2, 1 ) );
+ }
+
+ if( mbedtls_mpi_cmp_mpi( &TU, &TV ) >= 0 )
+ {
+ MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &TU, &TU, &TV ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U1, &U1, &V1 ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U2, &U2, &V2 ) );
+ }
+ else
+ {
+ MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &TV, &TV, &TU ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V1, &V1, &U1 ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V2, &V2, &U2 ) );
+ }
+ }
+ while( mbedtls_mpi_cmp_int( &TU, 0 ) != 0 );
+
+ while( mbedtls_mpi_cmp_int( &V1, 0 ) < 0 )
+ MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &V1, &V1, N ) );
+
+ while( mbedtls_mpi_cmp_mpi( &V1, N ) >= 0 )
+ MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V1, &V1, N ) );
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, &V1 ) );
+
+cleanup:
+
+ mbedtls_mpi_free( &TA ); mbedtls_mpi_free( &TU ); mbedtls_mpi_free( &U1 ); mbedtls_mpi_free( &U2 );
+ mbedtls_mpi_free( &G ); mbedtls_mpi_free( &TB ); mbedtls_mpi_free( &TV );
+ mbedtls_mpi_free( &V1 ); mbedtls_mpi_free( &V2 );
+
+ return( ret );
+}
+
+#if defined(MBEDTLS_GENPRIME)
+
+static const int small_prime[] =
+{
+ 3, 5, 7, 11, 13, 17, 19, 23,
+ 29, 31, 37, 41, 43, 47, 53, 59,
+ 61, 67, 71, 73, 79, 83, 89, 97,
+ 101, 103, 107, 109, 113, 127, 131, 137,
+ 139, 149, 151, 157, 163, 167, 173, 179,
+ 181, 191, 193, 197, 199, 211, 223, 227,
+ 229, 233, 239, 241, 251, 257, 263, 269,
+ 271, 277, 281, 283, 293, 307, 311, 313,
+ 317, 331, 337, 347, 349, 353, 359, 367,
+ 373, 379, 383, 389, 397, 401, 409, 419,
+ 421, 431, 433, 439, 443, 449, 457, 461,
+ 463, 467, 479, 487, 491, 499, 503, 509,
+ 521, 523, 541, 547, 557, 563, 569, 571,
+ 577, 587, 593, 599, 601, 607, 613, 617,
+ 619, 631, 641, 643, 647, 653, 659, 661,
+ 673, 677, 683, 691, 701, 709, 719, 727,
+ 733, 739, 743, 751, 757, 761, 769, 773,
+ 787, 797, 809, 811, 821, 823, 827, 829,
+ 839, 853, 857, 859, 863, 877, 881, 883,
+ 887, 907, 911, 919, 929, 937, 941, 947,
+ 953, 967, 971, 977, 983, 991, 997, -103
+};
+
+/*
+ * Small divisors test (X must be positive)
+ *
+ * Return values:
+ * 0: no small factor (possible prime, more tests needed)
+ * 1: certain prime
+ * MBEDTLS_ERR_MPI_NOT_ACCEPTABLE: certain non-prime
+ * other negative: error
+ */
+static int mpi_check_small_factors( const mbedtls_mpi *X )
+{
+ int ret = 0;
+ size_t i;
+ mbedtls_mpi_uint r;
+
+ if( ( X->p[0] & 1 ) == 0 )
+ return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE );
+
+ for( i = 0; small_prime[i] > 0; i++ )
+ {
+ if( mbedtls_mpi_cmp_int( X, small_prime[i] ) <= 0 )
+ return( 1 );
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, small_prime[i] ) );
+
+ if( r == 0 )
+ return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE );
+ }
+
+cleanup:
+ return( ret );
+}
+
+/*
+ * Miller-Rabin pseudo-primality test (HAC 4.24)
+ */
+static int mpi_miller_rabin( const mbedtls_mpi *X,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng )
+{
+ int ret, count;
+ size_t i, j, k, n, s;
+ mbedtls_mpi W, R, T, A, RR;
+
+ mbedtls_mpi_init( &W ); mbedtls_mpi_init( &R ); mbedtls_mpi_init( &T ); mbedtls_mpi_init( &A );
+ mbedtls_mpi_init( &RR );
+
+ /*
+ * W = |X| - 1
+ * R = W >> lsb( W )
+ */
+ MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &W, X, 1 ) );
+ s = mbedtls_mpi_lsb( &W );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R, &W ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &R, s ) );
+
+ i = mbedtls_mpi_bitlen( X );
+ /*
+ * HAC, table 4.4
+ */
+ n = ( ( i >= 1300 ) ? 2 : ( i >= 850 ) ? 3 :
+ ( i >= 650 ) ? 4 : ( i >= 350 ) ? 8 :
+ ( i >= 250 ) ? 12 : ( i >= 150 ) ? 18 : 27 );
+
+ for( i = 0; i < n; i++ )
+ {
+ /*
+ * pick a random A, 1 < A < |X| - 1
+ */
+ MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &A, X->n * ciL, f_rng, p_rng ) );
+
+ if( mbedtls_mpi_cmp_mpi( &A, &W ) >= 0 )
+ {
+ j = mbedtls_mpi_bitlen( &A ) - mbedtls_mpi_bitlen( &W );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &A, j + 1 ) );
+ }
+ A.p[0] |= 3;
+
+ count = 0;
+ do {
+ MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &A, X->n * ciL, f_rng, p_rng ) );
+
+ j = mbedtls_mpi_bitlen( &A );
+ k = mbedtls_mpi_bitlen( &W );
+ if (j > k) {
+ MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &A, j - k ) );
+ }
+
+ if (count++ > 30) {
+ return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
+ }
+
+ } while ( mbedtls_mpi_cmp_mpi( &A, &W ) >= 0 ||
+ mbedtls_mpi_cmp_int( &A, 1 ) <= 0 );
+
+ /*
+ * A = A^R mod |X|
+ */
+ MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &A, &A, &R, X, &RR ) );
+
+ if( mbedtls_mpi_cmp_mpi( &A, &W ) == 0 ||
+ mbedtls_mpi_cmp_int( &A, 1 ) == 0 )
+ continue;
+
+ j = 1;
+ while( j < s && mbedtls_mpi_cmp_mpi( &A, &W ) != 0 )
+ {
+ /*
+ * A = A * A mod |X|
+ */
+ MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, &A, &A ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &A, &T, X ) );
+
+ if( mbedtls_mpi_cmp_int( &A, 1 ) == 0 )
+ break;
+
+ j++;
+ }
+
+ /*
+ * not prime if A != |X| - 1 or A == 1
+ */
+ if( mbedtls_mpi_cmp_mpi( &A, &W ) != 0 ||
+ mbedtls_mpi_cmp_int( &A, 1 ) == 0 )
+ {
+ ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
+ break;
+ }
+ }
+
+cleanup:
+ mbedtls_mpi_free( &W ); mbedtls_mpi_free( &R ); mbedtls_mpi_free( &T ); mbedtls_mpi_free( &A );
+ mbedtls_mpi_free( &RR );
+
+ return( ret );
+}
+
+/*
+ * Pseudo-primality test: small factors, then Miller-Rabin
+ */
+int mbedtls_mpi_is_prime( const mbedtls_mpi *X,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng )
+{
+ int ret;
+ mbedtls_mpi XX;
+
+ XX.s = 1;
+ XX.n = X->n;
+ XX.p = X->p;
+
+ if( mbedtls_mpi_cmp_int( &XX, 0 ) == 0 ||
+ mbedtls_mpi_cmp_int( &XX, 1 ) == 0 )
+ return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE );
+
+ if( mbedtls_mpi_cmp_int( &XX, 2 ) == 0 )
+ return( 0 );
+
+ if( ( ret = mpi_check_small_factors( &XX ) ) != 0 )
+ {
+ if( ret == 1 )
+ return( 0 );
+
+ return( ret );
+ }
+
+ return( mpi_miller_rabin( &XX, f_rng, p_rng ) );
+}
+
+/*
+ * Prime number generation
+ */
+int mbedtls_mpi_gen_prime( mbedtls_mpi *X, size_t nbits, int dh_flag,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng )
+{
+ int ret;
+ size_t k, n;
+ mbedtls_mpi_uint r;
+ mbedtls_mpi Y;
+
+ if( nbits < 3 || nbits > MBEDTLS_MPI_MAX_BITS )
+ return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
+
+ mbedtls_mpi_init( &Y );
+
+ n = BITS_TO_LIMBS( nbits );
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( X, n * ciL, f_rng, p_rng ) );
+
+ k = mbedtls_mpi_bitlen( X );
+ if( k > nbits ) MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( X, k - nbits + 1 ) );
+
+ mbedtls_mpi_set_bit( X, nbits-1, 1 );
+
+ X->p[0] |= 1;
+
+ if( dh_flag == 0 )
+ {
+ while( ( ret = mbedtls_mpi_is_prime( X, f_rng, p_rng ) ) != 0 )
+ {
+ if( ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE )
+ goto cleanup;
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 2 ) );
+ }
+ }
+ else
+ {
+ /*
+ * An necessary condition for Y and X = 2Y + 1 to be prime
+ * is X = 2 mod 3 (which is equivalent to Y = 2 mod 3).
+ * Make sure it is satisfied, while keeping X = 3 mod 4
+ */
+
+ X->p[0] |= 2;
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, 3 ) );
+ if( r == 0 )
+ MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 8 ) );
+ else if( r == 1 )
+ MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 4 ) );
+
+ /* Set Y = (X-1) / 2, which is X / 2 because X is odd */
+ MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Y, X ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &Y, 1 ) );
+
+ while( 1 )
+ {
+ /*
+ * First, check small factors for X and Y
+ * before doing Miller-Rabin on any of them
+ */
+ if( ( ret = mpi_check_small_factors( X ) ) == 0 &&
+ ( ret = mpi_check_small_factors( &Y ) ) == 0 &&
+ ( ret = mpi_miller_rabin( X, f_rng, p_rng ) ) == 0 &&
+ ( ret = mpi_miller_rabin( &Y, f_rng, p_rng ) ) == 0 )
+ {
+ break;
+ }
+
+ if( ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE )
+ goto cleanup;
+
+ /*
+ * Next candidates. We want to preserve Y = (X-1) / 2 and
+ * Y = 1 mod 2 and Y = 2 mod 3 (eq X = 3 mod 4 and X = 2 mod 3)
+ * so up Y by 6 and X by 12.
+ */
+ MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 12 ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( &Y, &Y, 6 ) );
+ }
+ }
+
+cleanup:
+
+ mbedtls_mpi_free( &Y );
+
+ return( ret );
+}
+
+#endif /* MBEDTLS_GENPRIME */
+
+#if defined(MBEDTLS_SELF_TEST)
+
+#define GCD_PAIR_COUNT 3
+
+static const int gcd_pairs[GCD_PAIR_COUNT][3] =
+{
+ { 693, 609, 21 },
+ { 1764, 868, 28 },
+ { 768454923, 542167814, 1 }
+};
+
+/*
+ * Checkup routine
+ */
+int mbedtls_mpi_self_test( int verbose )
+{
+ int ret, i;
+ mbedtls_mpi A, E, N, X, Y, U, V;
+
+ mbedtls_mpi_init( &A ); mbedtls_mpi_init( &E ); mbedtls_mpi_init( &N ); mbedtls_mpi_init( &X );
+ mbedtls_mpi_init( &Y ); mbedtls_mpi_init( &U ); mbedtls_mpi_init( &V );
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &A, 16,
+ "EFE021C2645FD1DC586E69184AF4A31E" \
+ "D5F53E93B5F123FA41680867BA110131" \
+ "944FE7952E2517337780CB0DB80E61AA" \
+ "E7C8DDC6C5C6AADEB34EB38A2F40D5E6" ) );
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &E, 16,
+ "B2E7EFD37075B9F03FF989C7C5051C20" \
+ "34D2A323810251127E7BF8625A4F49A5" \
+ "F3E27F4DA8BD59C47D6DAABA4C8127BD" \
+ "5B5C25763222FEFCCFC38B832366C29E" ) );
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &N, 16,
+ "0066A198186C18C10B2F5ED9B522752A" \
+ "9830B69916E535C8F047518A889A43A5" \
+ "94B6BED27A168D31D4A52F88925AA8F5" ) );
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &X, &A, &N ) );
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16,
+ "602AB7ECA597A3D6B56FF9829A5E8B85" \
+ "9E857EA95A03512E2BAE7391688D264A" \
+ "A5663B0341DB9CCFD2C4C5F421FEC814" \
+ "8001B72E848A38CAE1C65F78E56ABDEF" \
+ "E12D3C039B8A02D6BE593F0BBBDA56F1" \
+ "ECF677152EF804370C1A305CAF3B5BF1" \
+ "30879B56C61DE584A0F53A2447A51E" ) );
+
+ if( verbose != 0 )
+ mbedtls_printf( " MPI test #1 (mul_mpi): " );
+
+ if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedtls_printf( "failed\n" );
+
+ ret = 1;
+ goto cleanup;
+ }
+
+ if( verbose != 0 )
+ mbedtls_printf( "passed\n" );
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( &X, &Y, &A, &N ) );
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16,
+ "256567336059E52CAE22925474705F39A94" ) );
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &V, 16,
+ "6613F26162223DF488E9CD48CC132C7A" \
+ "0AC93C701B001B092E4E5B9F73BCD27B" \
+ "9EE50D0657C77F374E903CDFA4C642" ) );
+
+ if( verbose != 0 )
+ mbedtls_printf( " MPI test #2 (div_mpi): " );
+
+ if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 ||
+ mbedtls_mpi_cmp_mpi( &Y, &V ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedtls_printf( "failed\n" );
+
+ ret = 1;
+ goto cleanup;
+ }
+
+ if( verbose != 0 )
+ mbedtls_printf( "passed\n" );
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &X, &A, &E, &N, NULL ) );
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16,
+ "36E139AEA55215609D2816998ED020BB" \
+ "BD96C37890F65171D948E9BC7CBAA4D9" \
+ "325D24D6A3C12710F10A09FA08AB87" ) );
+
+ if( verbose != 0 )
+ mbedtls_printf( " MPI test #3 (exp_mod): " );
+
+ if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedtls_printf( "failed\n" );
+
+ ret = 1;
+ goto cleanup;
+ }
+
+ if( verbose != 0 )
+ mbedtls_printf( "passed\n" );
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &X, &A, &N ) );
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16,
+ "003A0AAEDD7E784FC07D8F9EC6E3BFD5" \
+ "C3DBA76456363A10869622EAC2DD84EC" \
+ "C5B8A74DAC4D09E03B5E0BE779F2DF61" ) );
+
+ if( verbose != 0 )
+ mbedtls_printf( " MPI test #4 (inv_mod): " );
+
+ if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedtls_printf( "failed\n" );
+
+ ret = 1;
+ goto cleanup;
+ }
+
+ if( verbose != 0 )
+ mbedtls_printf( "passed\n" );
+
+ if( verbose != 0 )
+ mbedtls_printf( " MPI test #5 (simple gcd): " );
+
+ for( i = 0; i < GCD_PAIR_COUNT; i++ )
+ {
+ MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &X, gcd_pairs[i][0] ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &Y, gcd_pairs[i][1] ) );
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &A, &X, &Y ) );
+
+ if( mbedtls_mpi_cmp_int( &A, gcd_pairs[i][2] ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedtls_printf( "failed at %d\n", i );
+
+ ret = 1;
+ goto cleanup;
+ }
+ }
+
+ if( verbose != 0 )
+ mbedtls_printf( "passed\n" );
+
+cleanup:
+
+ if( ret != 0 && verbose != 0 )
+ mbedtls_printf( "Unexpected error, return code = %08X\n", ret );
+
+ mbedtls_mpi_free( &A ); mbedtls_mpi_free( &E ); mbedtls_mpi_free( &N ); mbedtls_mpi_free( &X );
+ mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &U ); mbedtls_mpi_free( &V );
+
+ if( verbose != 0 )
+ mbedtls_printf( "\n" );
+
+ return( ret );
+}
+
+#endif /* MBEDTLS_SELF_TEST */
+
+#endif /* MBEDTLS_BIGNUM_C */
diff --git a/backport/compat/verification/key.c b/backport/compat/verification/key.c
new file mode 100644
index 00000000..3a3c9bc5
--- /dev/null
+++ b/backport/compat/verification/key.c
@@ -0,0 +1,171 @@
+#include <linux/export.h>
+#include <linux/slab.h>
+#include <linux/key.h>
+#include <keys/asymmetric-type.h>
+#include "x509_parser.h"
+
+static void keyring_clear(struct key *keyring)
+{
+ struct key *key, *tmp;
+
+ if (!keyring->keyring)
+ return;
+
+ list_for_each_entry_safe(key, tmp, &keyring->list, list) {
+ WARN_ON(refcount_read(&key->refcount) > 1);
+ key_put(key);
+ }
+}
+
+void key_put(struct key *key)
+{
+ if (refcount_dec_and_test(&key->refcount)) {
+ keyring_clear(key);
+ list_del(&key->list);
+ kfree(key->description);
+ public_key_free(key->public_key);
+ public_key_signature_free(key->sig);
+ kfree(key->kids.id[0]);
+ kfree(key->kids.id[1]);
+ kfree(key);
+ }
+}
+EXPORT_SYMBOL_GPL(key_put);
+
+static struct key *key_alloc(void)
+{
+ struct key *key = kzalloc(sizeof(*key), GFP_KERNEL);
+
+ if (!key)
+ return NULL;
+ refcount_set(&key->refcount, 1);
+ INIT_LIST_HEAD(&key->list);
+
+ return key;
+}
+
+struct key *bp_keyring_alloc(void)
+{
+ struct key *key = key_alloc();
+
+ if (!key)
+ return NULL;
+
+ key->keyring = true;
+
+ return key;
+}
+EXPORT_SYMBOL_GPL(bp_keyring_alloc);
+
+key_ref_t bp_key_create_or_update(key_ref_t keyring,
+ const char *description,
+ const void *payload,
+ size_t plen)
+{
+ struct key *key = key_alloc();
+ struct x509_certificate *cert;
+ const char *q;
+ size_t srlen, sulen;
+ char *desc = NULL, *p;
+ int err;
+
+ if (!key)
+ return NULL;
+
+ cert = x509_cert_parse(payload, plen);
+ if (IS_ERR(cert)) {
+ err = PTR_ERR(cert);
+ goto free;
+ }
+
+ if (cert->unsupported_sig) {
+ public_key_signature_free(cert->sig);
+ cert->sig = NULL;
+ }
+
+ sulen = strlen(cert->subject);
+ if (cert->raw_skid) {
+ srlen = cert->raw_skid_size;
+ q = cert->raw_skid;
+ } else {
+ srlen = cert->raw_serial_size;
+ q = cert->raw_serial;
+ }
+
+ err = -ENOMEM;
+ desc = kmalloc(sulen + 2 + srlen * 2 + 1, GFP_KERNEL);
+ if (!desc)
+ goto free;
+ p = memcpy(desc, cert->subject, sulen);
+ p += sulen;
+ *p++ = ':';
+ *p++ = ' ';
+ p = bin2hex(p, q, srlen);
+ *p = 0;
+ key->description = desc;
+
+ key->kids.id[0] = cert->id;
+ key->kids.id[1] = cert->skid;
+ key->public_key = cert->pub;
+ key->sig = cert->sig;
+
+ cert->id = NULL;
+ cert->skid = NULL;
+ cert->pub = NULL;
+ cert->sig = NULL;
+ x509_free_certificate(cert);
+
+ refcount_inc(&key->refcount);
+ list_add_tail(&key->list, &key_ref_to_ptr(keyring)->list);
+
+ return make_key_ref(key, 0);
+free:
+ kfree(key);
+ return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(bp_key_create_or_update);
+
+struct key *find_asymmetric_key(struct key *keyring,
+ const struct asymmetric_key_id *id_0,
+ const struct asymmetric_key_id *id_1,
+ bool partial)
+{
+ struct key *key;
+
+ if (WARN_ON(partial))
+ return ERR_PTR(-ENOENT);
+ if (WARN_ON(!keyring))
+ return ERR_PTR(-EINVAL);
+
+ list_for_each_entry(key, &keyring->list, list) {
+ const struct asymmetric_key_ids *kids = &key->kids;
+
+ if (id_0 && (!kids->id[0] ||
+ !asymmetric_key_id_same(id_0, kids->id[0])))
+ continue;
+ if (id_1 && (!kids->id[1] ||
+ !asymmetric_key_id_same(id_0, kids->id[1])))
+ continue;
+
+ refcount_inc(&key->refcount);
+ return key;
+ }
+
+ return ERR_PTR(-ENOKEY);
+}
+
+struct asymmetric_key_id *
+asymmetric_key_generate_id(const void *val_1, size_t len_1,
+ const void *val_2, size_t len_2)
+{
+ struct asymmetric_key_id *kid;
+
+ kid = kmalloc(sizeof(struct asymmetric_key_id) + len_1 + len_2,
+ GFP_KERNEL);
+ if (!kid)
+ return ERR_PTR(-ENOMEM);
+ kid->len = len_1 + len_2;
+ memcpy(kid->data, val_1, len_1);
+ memcpy(kid->data + len_1, val_2, len_2);
+ return kid;
+}
diff --git a/backport/compat/verification/mbedtls/asn1.h b/backport/compat/verification/mbedtls/asn1.h
new file mode 100644
index 00000000..bc6b48b8
--- /dev/null
+++ b/backport/compat/verification/mbedtls/asn1.h
@@ -0,0 +1,344 @@
+/**
+ * \file asn1.h
+ *
+ * \brief Generic ASN.1 parsing
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: GPL-2.0
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * This file is part of mbed TLS (https://tls.mbed.org)
+ */
+#ifndef MBEDTLS_ASN1_H
+#define MBEDTLS_ASN1_H
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#include <stddef.h>
+
+#if defined(MBEDTLS_BIGNUM_C)
+#include "bignum.h"
+#endif
+
+/**
+ * \addtogroup asn1_module
+ * \{
+ */
+
+/**
+ * \name ASN1 Error codes
+ * These error codes are OR'ed to X509 error codes for
+ * higher error granularity.
+ * ASN1 is a standard to specify data structures.
+ * \{
+ */
+#define MBEDTLS_ERR_ASN1_OUT_OF_DATA -0x0060 /**< Out of data when parsing an ASN1 data structure. */
+#define MBEDTLS_ERR_ASN1_UNEXPECTED_TAG -0x0062 /**< ASN1 tag was of an unexpected value. */
+#define MBEDTLS_ERR_ASN1_INVALID_LENGTH -0x0064 /**< Error when trying to determine the length or invalid length. */
+#define MBEDTLS_ERR_ASN1_LENGTH_MISMATCH -0x0066 /**< Actual length differs from expected length. */
+#define MBEDTLS_ERR_ASN1_INVALID_DATA -0x0068 /**< Data is invalid. (not used) */
+#define MBEDTLS_ERR_ASN1_ALLOC_FAILED -0x006A /**< Memory allocation failed */
+#define MBEDTLS_ERR_ASN1_BUF_TOO_SMALL -0x006C /**< Buffer too small when writing ASN.1 data structure. */
+
+/* \} name */
+
+/**
+ * \name DER constants
+ * These constants comply with DER encoded the ANS1 type tags.
+ * DER encoding uses hexadecimal representation.
+ * An example DER sequence is:\n
+ * - 0x02 -- tag indicating INTEGER
+ * - 0x01 -- length in octets
+ * - 0x05 -- value
+ * Such sequences are typically read into \c ::mbedtls_x509_buf.
+ * \{
+ */
+#define MBEDTLS_ASN1_BOOLEAN 0x01
+#define MBEDTLS_ASN1_INTEGER 0x02
+#define MBEDTLS_ASN1_BIT_STRING 0x03
+#define MBEDTLS_ASN1_OCTET_STRING 0x04
+#define MBEDTLS_ASN1_NULL 0x05
+#define MBEDTLS_ASN1_OID 0x06
+#define MBEDTLS_ASN1_UTF8_STRING 0x0C
+#define MBEDTLS_ASN1_SEQUENCE 0x10
+#define MBEDTLS_ASN1_SET 0x11
+#define MBEDTLS_ASN1_PRINTABLE_STRING 0x13
+#define MBEDTLS_ASN1_T61_STRING 0x14
+#define MBEDTLS_ASN1_IA5_STRING 0x16
+#define MBEDTLS_ASN1_UTC_TIME 0x17
+#define MBEDTLS_ASN1_GENERALIZED_TIME 0x18
+#define MBEDTLS_ASN1_UNIVERSAL_STRING 0x1C
+#define MBEDTLS_ASN1_BMP_STRING 0x1E
+#define MBEDTLS_ASN1_PRIMITIVE 0x00
+#define MBEDTLS_ASN1_CONSTRUCTED 0x20
+#define MBEDTLS_ASN1_CONTEXT_SPECIFIC 0x80
+/* \} name */
+/* \} addtogroup asn1_module */
+
+/** Returns the size of the binary string, without the trailing \\0 */
+#define MBEDTLS_OID_SIZE(x) (sizeof(x) - 1)
+
+/**
+ * Compares an mbedtls_asn1_buf structure to a reference OID.
+ *
+ * Only works for 'defined' oid_str values (MBEDTLS_OID_HMAC_SHA1), you cannot use a
+ * 'unsigned char *oid' here!
+ */
+#define MBEDTLS_OID_CMP(oid_str, oid_buf) \
+ ( ( MBEDTLS_OID_SIZE(oid_str) != (oid_buf)->len ) || \
+ memcmp( (oid_str), (oid_buf)->p, (oid_buf)->len) != 0 )
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \name Functions to parse ASN.1 data structures
+ * \{
+ */
+
+/**
+ * Type-length-value structure that allows for ASN1 using DER.
+ */
+typedef struct mbedtls_asn1_buf
+{
+ int tag; /**< ASN1 type, e.g. MBEDTLS_ASN1_UTF8_STRING. */
+ size_t len; /**< ASN1 length, in octets. */
+ unsigned char *p; /**< ASN1 data, e.g. in ASCII. */
+}
+mbedtls_asn1_buf;
+
+/**
+ * Container for ASN1 bit strings.
+ */
+typedef struct mbedtls_asn1_bitstring
+{
+ size_t len; /**< ASN1 length, in octets. */
+ unsigned char unused_bits; /**< Number of unused bits at the end of the string */
+ unsigned char *p; /**< Raw ASN1 data for the bit string */
+}
+mbedtls_asn1_bitstring;
+
+/**
+ * Container for a sequence of ASN.1 items
+ */
+typedef struct mbedtls_asn1_sequence
+{
+ mbedtls_asn1_buf buf; /**< Buffer containing the given ASN.1 item. */
+ struct mbedtls_asn1_sequence *next; /**< The next entry in the sequence. */
+}
+mbedtls_asn1_sequence;
+
+/**
+ * Container for a sequence or list of 'named' ASN.1 data items
+ */
+typedef struct mbedtls_asn1_named_data
+{
+ mbedtls_asn1_buf oid; /**< The object identifier. */
+ mbedtls_asn1_buf val; /**< The named value. */
+ struct mbedtls_asn1_named_data *next; /**< The next entry in the sequence. */
+ unsigned char next_merged; /**< Merge next item into the current one? */
+}
+mbedtls_asn1_named_data;
+
+/**
+ * \brief Get the length of an ASN.1 element.
+ * Updates the pointer to immediately behind the length.
+ *
+ * \param p The position in the ASN.1 data
+ * \param end End of data
+ * \param len The variable that will receive the value
+ *
+ * \return 0 if successful, MBEDTLS_ERR_ASN1_OUT_OF_DATA on reaching
+ * end of data, MBEDTLS_ERR_ASN1_INVALID_LENGTH if length is
+ * unparseable.
+ */
+int mbedtls_asn1_get_len( unsigned char **p,
+ const unsigned char *end,
+ size_t *len );
+
+/**
+ * \brief Get the tag and length of the tag. Check for the requested tag.
+ * Updates the pointer to immediately behind the tag and length.
+ *
+ * \param p The position in the ASN.1 data
+ * \param end End of data
+ * \param len The variable that will receive the length
+ * \param tag The expected tag
+ *
+ * \return 0 if successful, MBEDTLS_ERR_ASN1_UNEXPECTED_TAG if tag did
+ * not match requested tag, or another specific ASN.1 error code.
+ */
+int mbedtls_asn1_get_tag( unsigned char **p,
+ const unsigned char *end,
+ size_t *len, int tag );
+
+/**
+ * \brief Retrieve a boolean ASN.1 tag and its value.
+ * Updates the pointer to immediately behind the full tag.
+ *
+ * \param p The position in the ASN.1 data
+ * \param end End of data
+ * \param val The variable that will receive the value
+ *
+ * \return 0 if successful or a specific ASN.1 error code.
+ */
+int mbedtls_asn1_get_bool( unsigned char **p,
+ const unsigned char *end,
+ int *val );
+
+/**
+ * \brief Retrieve an integer ASN.1 tag and its value.
+ * Updates the pointer to immediately behind the full tag.
+ *
+ * \param p The position in the ASN.1 data
+ * \param end End of data
+ * \param val The variable that will receive the value
+ *
+ * \return 0 if successful or a specific ASN.1 error code.
+ */
+int mbedtls_asn1_get_int( unsigned char **p,
+ const unsigned char *end,
+ int *val );
+
+/**
+ * \brief Retrieve a bitstring ASN.1 tag and its value.
+ * Updates the pointer to immediately behind the full tag.
+ *
+ * \param p The position in the ASN.1 data
+ * \param end End of data
+ * \param bs The variable that will receive the value
+ *
+ * \return 0 if successful or a specific ASN.1 error code.
+ */
+int mbedtls_asn1_get_bitstring( unsigned char **p, const unsigned char *end,
+ mbedtls_asn1_bitstring *bs);
+
+/**
+ * \brief Retrieve a bitstring ASN.1 tag without unused bits and its
+ * value.
+ * Updates the pointer to the beginning of the bit/octet string.
+ *
+ * \param p The position in the ASN.1 data
+ * \param end End of data
+ * \param len Length of the actual bit/octect string in bytes
+ *
+ * \return 0 if successful or a specific ASN.1 error code.
+ */
+int mbedtls_asn1_get_bitstring_null( unsigned char **p, const unsigned char *end,
+ size_t *len );
+
+/**
+ * \brief Parses and splits an ASN.1 "SEQUENCE OF <tag>"
+ * Updated the pointer to immediately behind the full sequence tag.
+ *
+ * \param p The position in the ASN.1 data
+ * \param end End of data
+ * \param cur First variable in the chain to fill
+ * \param tag Type of sequence
+ *
+ * \return 0 if successful or a specific ASN.1 error code.
+ */
+int mbedtls_asn1_get_sequence_of( unsigned char **p,
+ const unsigned char *end,
+ mbedtls_asn1_sequence *cur,
+ int tag);
+
+#if defined(MBEDTLS_BIGNUM_C)
+/**
+ * \brief Retrieve a MPI value from an integer ASN.1 tag.
+ * Updates the pointer to immediately behind the full tag.
+ *
+ * \param p The position in the ASN.1 data
+ * \param end End of data
+ * \param X The MPI that will receive the value
+ *
+ * \return 0 if successful or a specific ASN.1 or MPI error code.
+ */
+int mbedtls_asn1_get_mpi( unsigned char **p,
+ const unsigned char *end,
+ mbedtls_mpi *X );
+#endif /* MBEDTLS_BIGNUM_C */
+
+/**
+ * \brief Retrieve an AlgorithmIdentifier ASN.1 sequence.
+ * Updates the pointer to immediately behind the full
+ * AlgorithmIdentifier.
+ *
+ * \param p The position in the ASN.1 data
+ * \param end End of data
+ * \param alg The buffer to receive the OID
+ * \param params The buffer to receive the params (if any)
+ *
+ * \return 0 if successful or a specific ASN.1 or MPI error code.
+ */
+int mbedtls_asn1_get_alg( unsigned char **p,
+ const unsigned char *end,
+ mbedtls_asn1_buf *alg, mbedtls_asn1_buf *params );
+
+/**
+ * \brief Retrieve an AlgorithmIdentifier ASN.1 sequence with NULL or no
+ * params.
+ * Updates the pointer to immediately behind the full
+ * AlgorithmIdentifier.
+ *
+ * \param p The position in the ASN.1 data
+ * \param end End of data
+ * \param alg The buffer to receive the OID
+ *
+ * \return 0 if successful or a specific ASN.1 or MPI error code.
+ */
+int mbedtls_asn1_get_alg_null( unsigned char **p,
+ const unsigned char *end,
+ mbedtls_asn1_buf *alg );
+
+/**
+ * \brief Find a specific named_data entry in a sequence or list based on
+ * the OID.
+ *
+ * \param list The list to seek through
+ * \param oid The OID to look for
+ * \param len Size of the OID
+ *
+ * \return NULL if not found, or a pointer to the existing entry.
+ */
+mbedtls_asn1_named_data *mbedtls_asn1_find_named_data( mbedtls_asn1_named_data *list,
+ const char *oid, size_t len );
+
+/**
+ * \brief Free a mbedtls_asn1_named_data entry
+ *
+ * \param entry The named data entry to free
+ */
+void mbedtls_asn1_free_named_data( mbedtls_asn1_named_data *entry );
+
+/**
+ * \brief Free all entries in a mbedtls_asn1_named_data list
+ * Head will be set to NULL
+ *
+ * \param head Pointer to the head of the list of named data entries to free
+ */
+void mbedtls_asn1_free_named_data_list( mbedtls_asn1_named_data **head );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* asn1.h */
diff --git a/backport/compat/verification/mbedtls/bignum.h b/backport/compat/verification/mbedtls/bignum.h
new file mode 100644
index 00000000..69f8e2d9
--- /dev/null
+++ b/backport/compat/verification/mbedtls/bignum.h
@@ -0,0 +1,760 @@
+/**
+ * \file bignum.h
+ *
+ * \brief Multi-precision integer library
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: GPL-2.0
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * This file is part of mbed TLS (https://tls.mbed.org)
+ */
+#ifndef MBEDTLS_BIGNUM_H
+#define MBEDTLS_BIGNUM_H
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#if defined(MBEDTLS_FS_IO)
+#include <stdio.h>
+#endif
+
+#define MBEDTLS_ERR_MPI_FILE_IO_ERROR -0x0002 /**< An error occurred while reading from or writing to a file. */
+#define MBEDTLS_ERR_MPI_BAD_INPUT_DATA -0x0004 /**< Bad input parameters to function. */
+#define MBEDTLS_ERR_MPI_INVALID_CHARACTER -0x0006 /**< There is an invalid character in the digit string. */
+#define MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL -0x0008 /**< The buffer is too small to write to. */
+#define MBEDTLS_ERR_MPI_NEGATIVE_VALUE -0x000A /**< The input arguments are negative or result in illegal output. */
+#define MBEDTLS_ERR_MPI_DIVISION_BY_ZERO -0x000C /**< The input argument for division is zero, which is not allowed. */
+#define MBEDTLS_ERR_MPI_NOT_ACCEPTABLE -0x000E /**< The input arguments are not acceptable. */
+#define MBEDTLS_ERR_MPI_ALLOC_FAILED -0x0010 /**< Memory allocation failed. */
+
+#define MBEDTLS_MPI_CHK(f) do { if( ( ret = f ) != 0 ) goto cleanup; } while( 0 )
+
+/*
+ * Maximum size MPIs are allowed to grow to in number of limbs.
+ */
+#define MBEDTLS_MPI_MAX_LIMBS 10000
+
+#if !defined(MBEDTLS_MPI_WINDOW_SIZE)
+/*
+ * Maximum window size used for modular exponentiation. Default: 6
+ * Minimum value: 1. Maximum value: 6.
+ *
+ * Result is an array of ( 2 << MBEDTLS_MPI_WINDOW_SIZE ) MPIs used
+ * for the sliding window calculation. (So 64 by default)
+ *
+ * Reduction in size, reduces speed.
+ */
+#define MBEDTLS_MPI_WINDOW_SIZE 6 /**< Maximum windows size used. */
+#endif /* !MBEDTLS_MPI_WINDOW_SIZE */
+
+#if !defined(MBEDTLS_MPI_MAX_SIZE)
+/*
+ * Maximum size of MPIs allowed in bits and bytes for user-MPIs.
+ * ( Default: 512 bytes => 4096 bits, Maximum tested: 2048 bytes => 16384 bits )
+ *
+ * Note: Calculations can results temporarily in larger MPIs. So the number
+ * of limbs required (MBEDTLS_MPI_MAX_LIMBS) is higher.
+ */
+#define MBEDTLS_MPI_MAX_SIZE 1024 /**< Maximum number of bytes for usable MPIs. */
+#endif /* !MBEDTLS_MPI_MAX_SIZE */
+
+#define MBEDTLS_MPI_MAX_BITS ( 8 * MBEDTLS_MPI_MAX_SIZE ) /**< Maximum number of bits for usable MPIs. */
+
+/*
+ * When reading from files with mbedtls_mpi_read_file() and writing to files with
+ * mbedtls_mpi_write_file() the buffer should have space
+ * for a (short) label, the MPI (in the provided radix), the newline
+ * characters and the '\0'.
+ *
+ * By default we assume at least a 10 char label, a minimum radix of 10
+ * (decimal) and a maximum of 4096 bit numbers (1234 decimal chars).
+ * Autosized at compile time for at least a 10 char label, a minimum radix
+ * of 10 (decimal) for a number of MBEDTLS_MPI_MAX_BITS size.
+ *
+ * This used to be statically sized to 1250 for a maximum of 4096 bit
+ * numbers (1234 decimal chars).
+ *
+ * Calculate using the formula:
+ * MBEDTLS_MPI_RW_BUFFER_SIZE = ceil(MBEDTLS_MPI_MAX_BITS / ln(10) * ln(2)) +
+ * LabelSize + 6
+ */
+#define MBEDTLS_MPI_MAX_BITS_SCALE100 ( 100 * MBEDTLS_MPI_MAX_BITS )
+#define MBEDTLS_LN_2_DIV_LN_10_SCALE100 332
+#define MBEDTLS_MPI_RW_BUFFER_SIZE ( ((MBEDTLS_MPI_MAX_BITS_SCALE100 + MBEDTLS_LN_2_DIV_LN_10_SCALE100 - 1) / MBEDTLS_LN_2_DIV_LN_10_SCALE100) + 10 + 6 )
+
+/*
+ * Define the base integer type, architecture-wise.
+ *
+ * 32 or 64-bit integer types can be forced regardless of the underlying
+ * architecture by defining MBEDTLS_HAVE_INT32 or MBEDTLS_HAVE_INT64
+ * respectively and undefining MBEDTLS_HAVE_ASM.
+ *
+ * Double-width integers (e.g. 128-bit in 64-bit architectures) can be
+ * disabled by defining MBEDTLS_NO_UDBL_DIVISION.
+ */
+#if !defined(MBEDTLS_HAVE_INT32)
+ #if defined(_MSC_VER) && defined(_M_AMD64)
+ /* Always choose 64-bit when using MSC */
+ #if !defined(MBEDTLS_HAVE_INT64)
+ #define MBEDTLS_HAVE_INT64
+ #endif /* !MBEDTLS_HAVE_INT64 */
+ typedef int64_t mbedtls_mpi_sint;
+ typedef uint64_t mbedtls_mpi_uint;
+ #elif defined(__GNUC__) && ( \
+ defined(__amd64__) || defined(__x86_64__) || \
+ defined(__ppc64__) || defined(__powerpc64__) || \
+ defined(__ia64__) || defined(__alpha__) || \
+ ( defined(__sparc__) && defined(__arch64__) ) || \
+ defined(__s390x__) || defined(__mips64) )
+ #if !defined(MBEDTLS_HAVE_INT64)
+ #define MBEDTLS_HAVE_INT64
+ #endif /* MBEDTLS_HAVE_INT64 */
+ typedef int64_t mbedtls_mpi_sint;
+ typedef uint64_t mbedtls_mpi_uint;
+ #if !defined(MBEDTLS_NO_UDBL_DIVISION)
+ /* mbedtls_t_udbl defined as 128-bit unsigned int */
+ typedef unsigned int mbedtls_t_udbl __attribute__((mode(TI)));
+ #define MBEDTLS_HAVE_UDBL
+ #endif /* !MBEDTLS_NO_UDBL_DIVISION */
+ #elif defined(__ARMCC_VERSION) && defined(__aarch64__)
+ /*
+ * __ARMCC_VERSION is defined for both armcc and armclang and
+ * __aarch64__ is only defined by armclang when compiling 64-bit code
+ */
+ #if !defined(MBEDTLS_HAVE_INT64)
+ #define MBEDTLS_HAVE_INT64
+ #endif /* !MBEDTLS_HAVE_INT64 */
+ typedef int64_t mbedtls_mpi_sint;
+ typedef uint64_t mbedtls_mpi_uint;
+ #if !defined(MBEDTLS_NO_UDBL_DIVISION)
+ /* mbedtls_t_udbl defined as 128-bit unsigned int */
+ typedef __uint128_t mbedtls_t_udbl;
+ #define MBEDTLS_HAVE_UDBL
+ #endif /* !MBEDTLS_NO_UDBL_DIVISION */
+ #elif defined(MBEDTLS_HAVE_INT64)
+ /* Force 64-bit integers with unknown compiler */
+ typedef int64_t mbedtls_mpi_sint;
+ typedef uint64_t mbedtls_mpi_uint;
+ #endif
+#endif /* !MBEDTLS_HAVE_INT32 */
+
+#if !defined(MBEDTLS_HAVE_INT64)
+ /* Default to 32-bit compilation */
+ #if !defined(MBEDTLS_HAVE_INT32)
+ #define MBEDTLS_HAVE_INT32
+ #endif /* !MBEDTLS_HAVE_INT32 */
+ typedef int32_t mbedtls_mpi_sint;
+ typedef uint32_t mbedtls_mpi_uint;
+ #if !defined(MBEDTLS_NO_UDBL_DIVISION)
+ typedef uint64_t mbedtls_t_udbl;
+ #define MBEDTLS_HAVE_UDBL
+ #endif /* !MBEDTLS_NO_UDBL_DIVISION */
+#endif /* !MBEDTLS_HAVE_INT64 */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief MPI structure
+ */
+typedef struct
+{
+ int s; /*!< integer sign */
+ size_t n; /*!< total # of limbs */
+ mbedtls_mpi_uint *p; /*!< pointer to limbs */
+}
+mbedtls_mpi;
+
+/**
+ * \brief Initialize one MPI (make internal references valid)
+ * This just makes it ready to be set or freed,
+ * but does not define a value for the MPI.
+ *
+ * \param X One MPI to initialize.
+ */
+void mbedtls_mpi_init( mbedtls_mpi *X );
+
+/**
+ * \brief Unallocate one MPI
+ *
+ * \param X One MPI to unallocate.
+ */
+void mbedtls_mpi_free( mbedtls_mpi *X );
+
+/**
+ * \brief Enlarge to the specified number of limbs
+ *
+ * \param X MPI to grow
+ * \param nblimbs The target number of limbs
+ *
+ * \return 0 if successful,
+ * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed
+ */
+int mbedtls_mpi_grow( mbedtls_mpi *X, size_t nblimbs );
+
+/**
+ * \brief Resize down, keeping at least the specified number of limbs
+ *
+ * \param X MPI to shrink
+ * \param nblimbs The minimum number of limbs to keep
+ *
+ * \return 0 if successful,
+ * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed
+ */
+int mbedtls_mpi_shrink( mbedtls_mpi *X, size_t nblimbs );
+
+/**
+ * \brief Copy the contents of Y into X
+ *
+ * \param X Destination MPI
+ * \param Y Source MPI
+ *
+ * \return 0 if successful,
+ * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed
+ */
+int mbedtls_mpi_copy( mbedtls_mpi *X, const mbedtls_mpi *Y );
+
+/**
+ * \brief Swap the contents of X and Y
+ *
+ * \param X First MPI value
+ * \param Y Second MPI value
+ */
+void mbedtls_mpi_swap( mbedtls_mpi *X, mbedtls_mpi *Y );
+
+/**
+ * \brief Safe conditional assignement X = Y if assign is 1
+ *
+ * \param X MPI to conditionally assign to
+ * \param Y Value to be assigned
+ * \param assign 1: perform the assignment, 0: keep X's original value
+ *
+ * \return 0 if successful,
+ * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed,
+ *
+ * \note This function is equivalent to
+ * if( assign ) mbedtls_mpi_copy( X, Y );
+ * except that it avoids leaking any information about whether
+ * the assignment was done or not (the above code may leak
+ * information through branch prediction and/or memory access
+ * patterns analysis).
+ */
+int mbedtls_mpi_safe_cond_assign( mbedtls_mpi *X, const mbedtls_mpi *Y, unsigned char assign );
+
+/**
+ * \brief Safe conditional swap X <-> Y if swap is 1
+ *
+ * \param X First mbedtls_mpi value
+ * \param Y Second mbedtls_mpi value
+ * \param assign 1: perform the swap, 0: keep X and Y's original values
+ *
+ * \return 0 if successful,
+ * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed,
+ *
+ * \note This function is equivalent to
+ * if( assign ) mbedtls_mpi_swap( X, Y );
+ * except that it avoids leaking any information about whether
+ * the assignment was done or not (the above code may leak
+ * information through branch prediction and/or memory access
+ * patterns analysis).
+ */
+int mbedtls_mpi_safe_cond_swap( mbedtls_mpi *X, mbedtls_mpi *Y, unsigned char assign );
+
+/**
+ * \brief Set value from integer
+ *
+ * \param X MPI to set
+ * \param z Value to use
+ *
+ * \return 0 if successful,
+ * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed
+ */
+int mbedtls_mpi_lset( mbedtls_mpi *X, mbedtls_mpi_sint z );
+
+/**
+ * \brief Get a specific bit from X
+ *
+ * \param X MPI to use
+ * \param pos Zero-based index of the bit in X
+ *
+ * \return Either a 0 or a 1
+ */
+int mbedtls_mpi_get_bit( const mbedtls_mpi *X, size_t pos );
+
+/**
+ * \brief Set a bit of X to a specific value of 0 or 1
+ *
+ * \note Will grow X if necessary to set a bit to 1 in a not yet
+ * existing limb. Will not grow if bit should be set to 0
+ *
+ * \param X MPI to use
+ * \param pos Zero-based index of the bit in X
+ * \param val The value to set the bit to (0 or 1)
+ *
+ * \return 0 if successful,
+ * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed,
+ * MBEDTLS_ERR_MPI_BAD_INPUT_DATA if val is not 0 or 1
+ */
+int mbedtls_mpi_set_bit( mbedtls_mpi *X, size_t pos, unsigned char val );
+
+/**
+ * \brief Return the number of zero-bits before the least significant
+ * '1' bit
+ *
+ * Note: Thus also the zero-based index of the least significant '1' bit
+ *
+ * \param X MPI to use
+ */
+size_t mbedtls_mpi_lsb( const mbedtls_mpi *X );
+
+/**
+ * \brief Return the number of bits up to and including the most
+ * significant '1' bit'
+ *
+ * Note: Thus also the one-based index of the most significant '1' bit
+ *
+ * \param X MPI to use
+ */
+size_t mbedtls_mpi_bitlen( const mbedtls_mpi *X );
+
+/**
+ * \brief Return the total size in bytes
+ *
+ * \param X MPI to use
+ */
+size_t mbedtls_mpi_size( const mbedtls_mpi *X );
+
+/**
+ * \brief Import from an ASCII string
+ *
+ * \param X Destination MPI
+ * \param radix Input numeric base
+ * \param s Null-terminated string buffer
+ *
+ * \return 0 if successful, or a MBEDTLS_ERR_MPI_XXX error code
+ */
+int mbedtls_mpi_read_string( mbedtls_mpi *X, int radix, const char *s );
+
+/**
+ * \brief Export into an ASCII string
+ *
+ * \param X Source MPI
+ * \param radix Output numeric base
+ * \param buf Buffer to write the string to
+ * \param buflen Length of buf
+ * \param olen Length of the string written, including final NUL byte
+ *
+ * \return 0 if successful, or a MBEDTLS_ERR_MPI_XXX error code.
+ * *olen is always updated to reflect the amount
+ * of data that has (or would have) been written.
+ *
+ * \note Call this function with buflen = 0 to obtain the
+ * minimum required buffer size in *olen.
+ */
+int mbedtls_mpi_write_string( const mbedtls_mpi *X, int radix,
+ char *buf, size_t buflen, size_t *olen );
+
+#if defined(MBEDTLS_FS_IO)
+/**
+ * \brief Read MPI from a line in an opened file
+ *
+ * \param X Destination MPI
+ * \param radix Input numeric base
+ * \param fin Input file handle
+ *
+ * \return 0 if successful, MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if
+ * the file read buffer is too small or a
+ * MBEDTLS_ERR_MPI_XXX error code
+ *
+ * \note On success, this function advances the file stream
+ * to the end of the current line or to EOF.
+ *
+ * The function returns 0 on an empty line.
+ *
+ * Leading whitespaces are ignored, as is a
+ * '0x' prefix for radix 16.
+ *
+ */
+int mbedtls_mpi_read_file( mbedtls_mpi *X, int radix, FILE *fin );
+
+/**
+ * \brief Write X into an opened file, or stdout if fout is NULL
+ *
+ * \param p Prefix, can be NULL
+ * \param X Source MPI
+ * \param radix Output numeric base
+ * \param fout Output file handle (can be NULL)
+ *
+ * \return 0 if successful, or a MBEDTLS_ERR_MPI_XXX error code
+ *
+ * \note Set fout == NULL to print X on the console.
+ */
+int mbedtls_mpi_write_file( const char *p, const mbedtls_mpi *X, int radix, FILE *fout );
+#endif /* MBEDTLS_FS_IO */
+
+/**
+ * \brief Import X from unsigned binary data, big endian
+ *
+ * \param X Destination MPI
+ * \param buf Input buffer
+ * \param buflen Input buffer size
+ *
+ * \return 0 if successful,
+ * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed
+ */
+int mbedtls_mpi_read_binary( mbedtls_mpi *X, const unsigned char *buf, size_t buflen );
+
+/**
+ * \brief Export X into unsigned binary data, big endian.
+ * Always fills the whole buffer, which will start with zeros
+ * if the number is smaller.
+ *
+ * \param X Source MPI
+ * \param buf Output buffer
+ * \param buflen Output buffer size
+ *
+ * \return 0 if successful,
+ * MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if buf isn't large enough
+ */
+int mbedtls_mpi_write_binary( const mbedtls_mpi *X, unsigned char *buf, size_t buflen );
+
+/**
+ * \brief Left-shift: X <<= count
+ *
+ * \param X MPI to shift
+ * \param count Amount to shift
+ *
+ * \return 0 if successful,
+ * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed
+ */
+int mbedtls_mpi_shift_l( mbedtls_mpi *X, size_t count );
+
+/**
+ * \brief Right-shift: X >>= count
+ *
+ * \param X MPI to shift
+ * \param count Amount to shift
+ *
+ * \return 0 if successful,
+ * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed
+ */
+int mbedtls_mpi_shift_r( mbedtls_mpi *X, size_t count );
+
+/**
+ * \brief Compare unsigned values
+ *
+ * \param X Left-hand MPI
+ * \param Y Right-hand MPI
+ *
+ * \return 1 if |X| is greater than |Y|,
+ * -1 if |X| is lesser than |Y| or
+ * 0 if |X| is equal to |Y|
+ */
+int mbedtls_mpi_cmp_abs( const mbedtls_mpi *X, const mbedtls_mpi *Y );
+
+/**
+ * \brief Compare signed values
+ *
+ * \param X Left-hand MPI
+ * \param Y Right-hand MPI
+ *
+ * \return 1 if X is greater than Y,
+ * -1 if X is lesser than Y or
+ * 0 if X is equal to Y
+ */
+int mbedtls_mpi_cmp_mpi( const mbedtls_mpi *X, const mbedtls_mpi *Y );
+
+/**
+ * \brief Compare signed values
+ *
+ * \param X Left-hand MPI
+ * \param z The integer value to compare to
+ *
+ * \return 1 if X is greater than z,
+ * -1 if X is lesser than z or
+ * 0 if X is equal to z
+ */
+int mbedtls_mpi_cmp_int( const mbedtls_mpi *X, mbedtls_mpi_sint z );
+
+/**
+ * \brief Unsigned addition: X = |A| + |B|
+ *
+ * \param X Destination MPI
+ * \param A Left-hand MPI
+ * \param B Right-hand MPI
+ *
+ * \return 0 if successful,
+ * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed
+ */
+int mbedtls_mpi_add_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B );
+
+/**
+ * \brief Unsigned subtraction: X = |A| - |B|
+ *
+ * \param X Destination MPI
+ * \param A Left-hand MPI
+ * \param B Right-hand MPI
+ *
+ * \return 0 if successful,
+ * MBEDTLS_ERR_MPI_NEGATIVE_VALUE if B is greater than A
+ */
+int mbedtls_mpi_sub_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B );
+
+/**
+ * \brief Signed addition: X = A + B
+ *
+ * \param X Destination MPI
+ * \param A Left-hand MPI
+ * \param B Right-hand MPI
+ *
+ * \return 0 if successful,
+ * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed
+ */
+int mbedtls_mpi_add_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B );
+
+/**
+ * \brief Signed subtraction: X = A - B
+ *
+ * \param X Destination MPI
+ * \param A Left-hand MPI
+ * \param B Right-hand MPI
+ *
+ * \return 0 if successful,
+ * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed
+ */
+int mbedtls_mpi_sub_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B );
+
+/**
+ * \brief Signed addition: X = A + b
+ *
+ * \param X Destination MPI
+ * \param A Left-hand MPI
+ * \param b The integer value to add
+ *
+ * \return 0 if successful,
+ * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed
+ */
+int mbedtls_mpi_add_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b );
+
+/**
+ * \brief Signed subtraction: X = A - b
+ *
+ * \param X Destination MPI
+ * \param A Left-hand MPI
+ * \param b The integer value to subtract
+ *
+ * \return 0 if successful,
+ * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed
+ */
+int mbedtls_mpi_sub_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b );
+
+/**
+ * \brief Baseline multiplication: X = A * B
+ *
+ * \param X Destination MPI
+ * \param A Left-hand MPI
+ * \param B Right-hand MPI
+ *
+ * \return 0 if successful,
+ * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed
+ */
+int mbedtls_mpi_mul_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B );
+
+/**
+ * \brief Baseline multiplication: X = A * b
+ *
+ * \param X Destination MPI
+ * \param A Left-hand MPI
+ * \param b The unsigned integer value to multiply with
+ *
+ * \note b is unsigned
+ *
+ * \return 0 if successful,
+ * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed
+ */
+int mbedtls_mpi_mul_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_uint b );
+
+/**
+ * \brief Division by mbedtls_mpi: A = Q * B + R
+ *
+ * \param Q Destination MPI for the quotient
+ * \param R Destination MPI for the rest value
+ * \param A Left-hand MPI
+ * \param B Right-hand MPI
+ *
+ * \return 0 if successful,
+ * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed,
+ * MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if B == 0
+ *
+ * \note Either Q or R can be NULL.
+ */
+int mbedtls_mpi_div_mpi( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B );
+
+/**
+ * \brief Division by int: A = Q * b + R
+ *
+ * \param Q Destination MPI for the quotient
+ * \param R Destination MPI for the rest value
+ * \param A Left-hand MPI
+ * \param b Integer to divide by
+ *
+ * \return 0 if successful,
+ * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed,
+ * MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if b == 0
+ *
+ * \note Either Q or R can be NULL.
+ */
+int mbedtls_mpi_div_int( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, mbedtls_mpi_sint b );
+
+/**
+ * \brief Modulo: R = A mod B
+ *
+ * \param R Destination MPI for the rest value
+ * \param A Left-hand MPI
+ * \param B Right-hand MPI
+ *
+ * \return 0 if successful,
+ * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed,
+ * MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if B == 0,
+ * MBEDTLS_ERR_MPI_NEGATIVE_VALUE if B < 0
+ */
+int mbedtls_mpi_mod_mpi( mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B );
+
+/**
+ * \brief Modulo: r = A mod b
+ *
+ * \param r Destination mbedtls_mpi_uint
+ * \param A Left-hand MPI
+ * \param b Integer to divide by
+ *
+ * \return 0 if successful,
+ * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed,
+ * MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if b == 0,
+ * MBEDTLS_ERR_MPI_NEGATIVE_VALUE if b < 0
+ */
+int mbedtls_mpi_mod_int( mbedtls_mpi_uint *r, const mbedtls_mpi *A, mbedtls_mpi_sint b );
+
+/**
+ * \brief Sliding-window exponentiation: X = A^E mod N
+ *
+ * \param X Destination MPI
+ * \param A Left-hand MPI
+ * \param E Exponent MPI
+ * \param N Modular MPI
+ * \param _RR Speed-up MPI used for recalculations
+ *
+ * \return 0 if successful,
+ * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed,
+ * MBEDTLS_ERR_MPI_BAD_INPUT_DATA if N is negative or even or
+ * if E is negative
+ *
+ * \note _RR is used to avoid re-computing R*R mod N across
+ * multiple calls, which speeds up things a bit. It can
+ * be set to NULL if the extra performance is unneeded.
+ */
+int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *E, const mbedtls_mpi *N, mbedtls_mpi *_RR );
+
+/**
+ * \brief Fill an MPI X with size bytes of random
+ *
+ * \param X Destination MPI
+ * \param size Size in bytes
+ * \param f_rng RNG function
+ * \param p_rng RNG parameter
+ *
+ * \return 0 if successful,
+ * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed
+ */
+int mbedtls_mpi_fill_random( mbedtls_mpi *X, size_t size,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng );
+
+/**
+ * \brief Greatest common divisor: G = gcd(A, B)
+ *
+ * \param G Destination MPI
+ * \param A Left-hand MPI
+ * \param B Right-hand MPI
+ *
+ * \return 0 if successful,
+ * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed
+ */
+int mbedtls_mpi_gcd( mbedtls_mpi *G, const mbedtls_mpi *A, const mbedtls_mpi *B );
+
+/**
+ * \brief Modular inverse: X = A^-1 mod N
+ *
+ * \param X Destination MPI
+ * \param A Left-hand MPI
+ * \param N Right-hand MPI
+ *
+ * \return 0 if successful,
+ * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed,
+ * MBEDTLS_ERR_MPI_BAD_INPUT_DATA if N is <= 1,
+ MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if A has no inverse mod N.
+ */
+int mbedtls_mpi_inv_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *N );
+
+/**
+ * \brief Miller-Rabin primality test
+ *
+ * \param X MPI to check
+ * \param f_rng RNG function
+ * \param p_rng RNG parameter
+ *
+ * \return 0 if successful (probably prime),
+ * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed,
+ * MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if X is not prime
+ */
+int mbedtls_mpi_is_prime( const mbedtls_mpi *X,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng );
+
+/**
+ * \brief Prime number generation
+ *
+ * \param X Destination MPI
+ * \param nbits Required size of X in bits
+ * ( 3 <= nbits <= MBEDTLS_MPI_MAX_BITS )
+ * \param dh_flag If 1, then (X-1)/2 will be prime too
+ * \param f_rng RNG function
+ * \param p_rng RNG parameter
+ *
+ * \return 0 if successful (probably prime),
+ * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed,
+ * MBEDTLS_ERR_MPI_BAD_INPUT_DATA if nbits is < 3
+ */
+int mbedtls_mpi_gen_prime( mbedtls_mpi *X, size_t nbits, int dh_flag,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng );
+
+/**
+ * \brief Checkup routine
+ *
+ * \return 0 if successful, or 1 if the test failed
+ */
+int mbedtls_mpi_self_test( int verbose );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* bignum.h */
diff --git a/backport/compat/verification/mbedtls/bn_mul.h b/backport/compat/verification/mbedtls/bn_mul.h
new file mode 100644
index 00000000..5f59ec64
--- /dev/null
+++ b/backport/compat/verification/mbedtls/bn_mul.h
@@ -0,0 +1,887 @@
+/**
+ * \file bn_mul.h
+ *
+ * \brief Multi-precision integer library
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: GPL-2.0
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * This file is part of mbed TLS (https://tls.mbed.org)
+ */
+/*
+ * Multiply source vector [s] with b, add result
+ * to destination vector [d] and set carry c.
+ *
+ * Currently supports:
+ *
+ * . IA-32 (386+) . AMD64 / EM64T
+ * . IA-32 (SSE2) . Motorola 68000
+ * . PowerPC, 32-bit . MicroBlaze
+ * . PowerPC, 64-bit . TriCore
+ * . SPARC v8 . ARM v3+
+ * . Alpha . MIPS32
+ * . C, longlong . C, generic
+ */
+#ifndef MBEDTLS_BN_MUL_H
+#define MBEDTLS_BN_MUL_H
+
+#include "bignum.h"
+
+#if defined(MBEDTLS_HAVE_ASM)
+
+#ifndef asm
+#define asm __asm
+#endif
+
+/* armcc5 --gnu defines __GNUC__ but doesn't support GNU's extended asm */
+#if defined(__GNUC__) && \
+ ( !defined(__ARMCC_VERSION) || __ARMCC_VERSION >= 6000000 )
+#if defined(__i386__)
+
+#define MULADDC_INIT \
+ asm( \
+ "movl %%ebx, %0 \n\t" \
+ "movl %5, %%esi \n\t" \
+ "movl %6, %%edi \n\t" \
+ "movl %7, %%ecx \n\t" \
+ "movl %8, %%ebx \n\t"
+
+#define MULADDC_CORE \
+ "lodsl \n\t" \
+ "mull %%ebx \n\t" \
+ "addl %%ecx, %%eax \n\t" \
+ "adcl $0, %%edx \n\t" \
+ "addl (%%edi), %%eax \n\t" \
+ "adcl $0, %%edx \n\t" \
+ "movl %%edx, %%ecx \n\t" \
+ "stosl \n\t"
+
+#if defined(MBEDTLS_HAVE_SSE2)
+
+#define MULADDC_HUIT \
+ "movd %%ecx, %%mm1 \n\t" \
+ "movd %%ebx, %%mm0 \n\t" \
+ "movd (%%edi), %%mm3 \n\t" \
+ "paddq %%mm3, %%mm1 \n\t" \
+ "movd (%%esi), %%mm2 \n\t" \
+ "pmuludq %%mm0, %%mm2 \n\t" \
+ "movd 4(%%esi), %%mm4 \n\t" \
+ "pmuludq %%mm0, %%mm4 \n\t" \
+ "movd 8(%%esi), %%mm6 \n\t" \
+ "pmuludq %%mm0, %%mm6 \n\t" \
+ "movd 12(%%esi), %%mm7 \n\t" \
+ "pmuludq %%mm0, %%mm7 \n\t" \
+ "paddq %%mm2, %%mm1 \n\t" \
+ "movd 4(%%edi), %%mm3 \n\t" \
+ "paddq %%mm4, %%mm3 \n\t" \
+ "movd 8(%%edi), %%mm5 \n\t" \
+ "paddq %%mm6, %%mm5 \n\t" \
+ "movd 12(%%edi), %%mm4 \n\t" \
+ "paddq %%mm4, %%mm7 \n\t" \
+ "movd %%mm1, (%%edi) \n\t" \
+ "movd 16(%%esi), %%mm2 \n\t" \
+ "pmuludq %%mm0, %%mm2 \n\t" \
+ "psrlq $32, %%mm1 \n\t" \
+ "movd 20(%%esi), %%mm4 \n\t" \
+ "pmuludq %%mm0, %%mm4 \n\t" \
+ "paddq %%mm3, %%mm1 \n\t" \
+ "movd 24(%%esi), %%mm6 \n\t" \
+ "pmuludq %%mm0, %%mm6 \n\t" \
+ "movd %%mm1, 4(%%edi) \n\t" \
+ "psrlq $32, %%mm1 \n\t" \
+ "movd 28(%%esi), %%mm3 \n\t" \
+ "pmuludq %%mm0, %%mm3 \n\t" \
+ "paddq %%mm5, %%mm1 \n\t" \
+ "movd 16(%%edi), %%mm5 \n\t" \
+ "paddq %%mm5, %%mm2 \n\t" \
+ "movd %%mm1, 8(%%edi) \n\t" \
+ "psrlq $32, %%mm1 \n\t" \
+ "paddq %%mm7, %%mm1 \n\t" \
+ "movd 20(%%edi), %%mm5 \n\t" \
+ "paddq %%mm5, %%mm4 \n\t" \
+ "movd %%mm1, 12(%%edi) \n\t" \
+ "psrlq $32, %%mm1 \n\t" \
+ "paddq %%mm2, %%mm1 \n\t" \
+ "movd 24(%%edi), %%mm5 \n\t" \
+ "paddq %%mm5, %%mm6 \n\t" \
+ "movd %%mm1, 16(%%edi) \n\t" \
+ "psrlq $32, %%mm1 \n\t" \
+ "paddq %%mm4, %%mm1 \n\t" \
+ "movd 28(%%edi), %%mm5 \n\t" \
+ "paddq %%mm5, %%mm3 \n\t" \
+ "movd %%mm1, 20(%%edi) \n\t" \
+ "psrlq $32, %%mm1 \n\t" \
+ "paddq %%mm6, %%mm1 \n\t" \
+ "movd %%mm1, 24(%%edi) \n\t" \
+ "psrlq $32, %%mm1 \n\t" \
+ "paddq %%mm3, %%mm1 \n\t" \
+ "movd %%mm1, 28(%%edi) \n\t" \
+ "addl $32, %%edi \n\t" \
+ "addl $32, %%esi \n\t" \
+ "psrlq $32, %%mm1 \n\t" \
+ "movd %%mm1, %%ecx \n\t"
+
+#define MULADDC_STOP \
+ "emms \n\t" \
+ "movl %4, %%ebx \n\t" \
+ "movl %%ecx, %1 \n\t" \
+ "movl %%edi, %2 \n\t" \
+ "movl %%esi, %3 \n\t" \
+ : "=m" (t), "=m" (c), "=m" (d), "=m" (s) \
+ : "m" (t), "m" (s), "m" (d), "m" (c), "m" (b) \
+ : "eax", "ecx", "edx", "esi", "edi" \
+ );
+
+#else
+
+#define MULADDC_STOP \
+ "movl %4, %%ebx \n\t" \
+ "movl %%ecx, %1 \n\t" \
+ "movl %%edi, %2 \n\t" \
+ "movl %%esi, %3 \n\t" \
+ : "=m" (t), "=m" (c), "=m" (d), "=m" (s) \
+ : "m" (t), "m" (s), "m" (d), "m" (c), "m" (b) \
+ : "eax", "ecx", "edx", "esi", "edi" \
+ );
+#endif /* SSE2 */
+#endif /* i386 */
+
+#if defined(__amd64__) || defined (__x86_64__)
+
+#define MULADDC_INIT \
+ asm( \
+ "xorq %%r8, %%r8 \n\t"
+
+#define MULADDC_CORE \
+ "movq (%%rsi), %%rax \n\t" \
+ "mulq %%rbx \n\t" \
+ "addq $8, %%rsi \n\t" \
+ "addq %%rcx, %%rax \n\t" \
+ "movq %%r8, %%rcx \n\t" \
+ "adcq $0, %%rdx \n\t" \
+ "nop \n\t" \
+ "addq %%rax, (%%rdi) \n\t" \
+ "adcq %%rdx, %%rcx \n\t" \
+ "addq $8, %%rdi \n\t"
+
+#define MULADDC_STOP \
+ : "+c" (c), "+D" (d), "+S" (s) \
+ : "b" (b) \
+ : "rax", "rdx", "r8" \
+ );
+
+#endif /* AMD64 */
+
+#if defined(__mc68020__) || defined(__mcpu32__)
+
+#define MULADDC_INIT \
+ asm( \
+ "movl %3, %%a2 \n\t" \
+ "movl %4, %%a3 \n\t" \
+ "movl %5, %%d3 \n\t" \
+ "movl %6, %%d2 \n\t" \
+ "moveq #0, %%d0 \n\t"
+
+#define MULADDC_CORE \
+ "movel %%a2@+, %%d1 \n\t" \
+ "mulul %%d2, %%d4:%%d1 \n\t" \
+ "addl %%d3, %%d1 \n\t" \
+ "addxl %%d0, %%d4 \n\t" \
+ "moveq #0, %%d3 \n\t" \
+ "addl %%d1, %%a3@+ \n\t" \
+ "addxl %%d4, %%d3 \n\t"
+
+#define MULADDC_STOP \
+ "movl %%d3, %0 \n\t" \
+ "movl %%a3, %1 \n\t" \
+ "movl %%a2, %2 \n\t" \
+ : "=m" (c), "=m" (d), "=m" (s) \
+ : "m" (s), "m" (d), "m" (c), "m" (b) \
+ : "d0", "d1", "d2", "d3", "d4", "a2", "a3" \
+ );
+
+#define MULADDC_HUIT \
+ "movel %%a2@+, %%d1 \n\t" \
+ "mulul %%d2, %%d4:%%d1 \n\t" \
+ "addxl %%d3, %%d1 \n\t" \
+ "addxl %%d0, %%d4 \n\t" \
+ "addl %%d1, %%a3@+ \n\t" \
+ "movel %%a2@+, %%d1 \n\t" \
+ "mulul %%d2, %%d3:%%d1 \n\t" \
+ "addxl %%d4, %%d1 \n\t" \
+ "addxl %%d0, %%d3 \n\t" \
+ "addl %%d1, %%a3@+ \n\t" \
+ "movel %%a2@+, %%d1 \n\t" \
+ "mulul %%d2, %%d4:%%d1 \n\t" \
+ "addxl %%d3, %%d1 \n\t" \
+ "addxl %%d0, %%d4 \n\t" \
+ "addl %%d1, %%a3@+ \n\t" \
+ "movel %%a2@+, %%d1 \n\t" \
+ "mulul %%d2, %%d3:%%d1 \n\t" \
+ "addxl %%d4, %%d1 \n\t" \
+ "addxl %%d0, %%d3 \n\t" \
+ "addl %%d1, %%a3@+ \n\t" \
+ "movel %%a2@+, %%d1 \n\t" \
+ "mulul %%d2, %%d4:%%d1 \n\t" \
+ "addxl %%d3, %%d1 \n\t" \
+ "addxl %%d0, %%d4 \n\t" \
+ "addl %%d1, %%a3@+ \n\t" \
+ "movel %%a2@+, %%d1 \n\t" \
+ "mulul %%d2, %%d3:%%d1 \n\t" \
+ "addxl %%d4, %%d1 \n\t" \
+ "addxl %%d0, %%d3 \n\t" \
+ "addl %%d1, %%a3@+ \n\t" \
+ "movel %%a2@+, %%d1 \n\t" \
+ "mulul %%d2, %%d4:%%d1 \n\t" \
+ "addxl %%d3, %%d1 \n\t" \
+ "addxl %%d0, %%d4 \n\t" \
+ "addl %%d1, %%a3@+ \n\t" \
+ "movel %%a2@+, %%d1 \n\t" \
+ "mulul %%d2, %%d3:%%d1 \n\t" \
+ "addxl %%d4, %%d1 \n\t" \
+ "addxl %%d0, %%d3 \n\t" \
+ "addl %%d1, %%a3@+ \n\t" \
+ "addxl %%d0, %%d3 \n\t"
+
+#endif /* MC68000 */
+
+#if defined(__powerpc64__) || defined(__ppc64__)
+
+#if defined(__MACH__) && defined(__APPLE__)
+
+#define MULADDC_INIT \
+ asm( \
+ "ld r3, %3 \n\t" \
+ "ld r4, %4 \n\t" \
+ "ld r5, %5 \n\t" \
+ "ld r6, %6 \n\t" \
+ "addi r3, r3, -8 \n\t" \
+ "addi r4, r4, -8 \n\t" \
+ "addic r5, r5, 0 \n\t"
+
+#define MULADDC_CORE \
+ "ldu r7, 8(r3) \n\t" \
+ "mulld r8, r7, r6 \n\t" \
+ "mulhdu r9, r7, r6 \n\t" \
+ "adde r8, r8, r5 \n\t" \
+ "ld r7, 8(r4) \n\t" \
+ "addze r5, r9 \n\t" \
+ "addc r8, r8, r7 \n\t" \
+ "stdu r8, 8(r4) \n\t"
+
+#define MULADDC_STOP \
+ "addze r5, r5 \n\t" \
+ "addi r4, r4, 8 \n\t" \
+ "addi r3, r3, 8 \n\t" \
+ "std r5, %0 \n\t" \
+ "std r4, %1 \n\t" \
+ "std r3, %2 \n\t" \
+ : "=m" (c), "=m" (d), "=m" (s) \
+ : "m" (s), "m" (d), "m" (c), "m" (b) \
+ : "r3", "r4", "r5", "r6", "r7", "r8", "r9" \
+ );
+
+
+#else /* __MACH__ && __APPLE__ */
+
+#define MULADDC_INIT \
+ asm( \
+ "ld %%r3, %3 \n\t" \
+ "ld %%r4, %4 \n\t" \
+ "ld %%r5, %5 \n\t" \
+ "ld %%r6, %6 \n\t" \
+ "addi %%r3, %%r3, -8 \n\t" \
+ "addi %%r4, %%r4, -8 \n\t" \
+ "addic %%r5, %%r5, 0 \n\t"
+
+#define MULADDC_CORE \
+ "ldu %%r7, 8(%%r3) \n\t" \
+ "mulld %%r8, %%r7, %%r6 \n\t" \
+ "mulhdu %%r9, %%r7, %%r6 \n\t" \
+ "adde %%r8, %%r8, %%r5 \n\t" \
+ "ld %%r7, 8(%%r4) \n\t" \
+ "addze %%r5, %%r9 \n\t" \
+ "addc %%r8, %%r8, %%r7 \n\t" \
+ "stdu %%r8, 8(%%r4) \n\t"
+
+#define MULADDC_STOP \
+ "addze %%r5, %%r5 \n\t" \
+ "addi %%r4, %%r4, 8 \n\t" \
+ "addi %%r3, %%r3, 8 \n\t" \
+ "std %%r5, %0 \n\t" \
+ "std %%r4, %1 \n\t" \
+ "std %%r3, %2 \n\t" \
+ : "=m" (c), "=m" (d), "=m" (s) \
+ : "m" (s), "m" (d), "m" (c), "m" (b) \
+ : "r3", "r4", "r5", "r6", "r7", "r8", "r9" \
+ );
+
+#endif /* __MACH__ && __APPLE__ */
+
+#elif defined(__powerpc__) || defined(__ppc__) /* end PPC64/begin PPC32 */
+
+#if defined(__MACH__) && defined(__APPLE__)
+
+#define MULADDC_INIT \
+ asm( \
+ "lwz r3, %3 \n\t" \
+ "lwz r4, %4 \n\t" \
+ "lwz r5, %5 \n\t" \
+ "lwz r6, %6 \n\t" \
+ "addi r3, r3, -4 \n\t" \
+ "addi r4, r4, -4 \n\t" \
+ "addic r5, r5, 0 \n\t"
+
+#define MULADDC_CORE \
+ "lwzu r7, 4(r3) \n\t" \
+ "mullw r8, r7, r6 \n\t" \
+ "mulhwu r9, r7, r6 \n\t" \
+ "adde r8, r8, r5 \n\t" \
+ "lwz r7, 4(r4) \n\t" \
+ "addze r5, r9 \n\t" \
+ "addc r8, r8, r7 \n\t" \
+ "stwu r8, 4(r4) \n\t"
+
+#define MULADDC_STOP \
+ "addze r5, r5 \n\t" \
+ "addi r4, r4, 4 \n\t" \
+ "addi r3, r3, 4 \n\t" \
+ "stw r5, %0 \n\t" \
+ "stw r4, %1 \n\t" \
+ "stw r3, %2 \n\t" \
+ : "=m" (c), "=m" (d), "=m" (s) \
+ : "m" (s), "m" (d), "m" (c), "m" (b) \
+ : "r3", "r4", "r5", "r6", "r7", "r8", "r9" \
+ );
+
+#else /* __MACH__ && __APPLE__ */
+
+#define MULADDC_INIT \
+ asm( \
+ "lwz %%r3, %3 \n\t" \
+ "lwz %%r4, %4 \n\t" \
+ "lwz %%r5, %5 \n\t" \
+ "lwz %%r6, %6 \n\t" \
+ "addi %%r3, %%r3, -4 \n\t" \
+ "addi %%r4, %%r4, -4 \n\t" \
+ "addic %%r5, %%r5, 0 \n\t"
+
+#define MULADDC_CORE \
+ "lwzu %%r7, 4(%%r3) \n\t" \
+ "mullw %%r8, %%r7, %%r6 \n\t" \
+ "mulhwu %%r9, %%r7, %%r6 \n\t" \
+ "adde %%r8, %%r8, %%r5 \n\t" \
+ "lwz %%r7, 4(%%r4) \n\t" \
+ "addze %%r5, %%r9 \n\t" \
+ "addc %%r8, %%r8, %%r7 \n\t" \
+ "stwu %%r8, 4(%%r4) \n\t"
+
+#define MULADDC_STOP \
+ "addze %%r5, %%r5 \n\t" \
+ "addi %%r4, %%r4, 4 \n\t" \
+ "addi %%r3, %%r3, 4 \n\t" \
+ "stw %%r5, %0 \n\t" \
+ "stw %%r4, %1 \n\t" \
+ "stw %%r3, %2 \n\t" \
+ : "=m" (c), "=m" (d), "=m" (s) \
+ : "m" (s), "m" (d), "m" (c), "m" (b) \
+ : "r3", "r4", "r5", "r6", "r7", "r8", "r9" \
+ );
+
+#endif /* __MACH__ && __APPLE__ */
+
+#endif /* PPC32 */
+
+/*
+ * The Sparc(64) assembly is reported to be broken.
+ * Disable it for now, until we're able to fix it.
+ */
+#if 0 && defined(__sparc__)
+#if defined(__sparc64__)
+
+#define MULADDC_INIT \
+ asm( \
+ "ldx %3, %%o0 \n\t" \
+ "ldx %4, %%o1 \n\t" \
+ "ld %5, %%o2 \n\t" \
+ "ld %6, %%o3 \n\t"
+
+#define MULADDC_CORE \
+ "ld [%%o0], %%o4 \n\t" \
+ "inc 4, %%o0 \n\t" \
+ "ld [%%o1], %%o5 \n\t" \
+ "umul %%o3, %%o4, %%o4 \n\t" \
+ "addcc %%o4, %%o2, %%o4 \n\t" \
+ "rd %%y, %%g1 \n\t" \
+ "addx %%g1, 0, %%g1 \n\t" \
+ "addcc %%o4, %%o5, %%o4 \n\t" \
+ "st %%o4, [%%o1] \n\t" \
+ "addx %%g1, 0, %%o2 \n\t" \
+ "inc 4, %%o1 \n\t"
+
+ #define MULADDC_STOP \
+ "st %%o2, %0 \n\t" \
+ "stx %%o1, %1 \n\t" \
+ "stx %%o0, %2 \n\t" \
+ : "=m" (c), "=m" (d), "=m" (s) \
+ : "m" (s), "m" (d), "m" (c), "m" (b) \
+ : "g1", "o0", "o1", "o2", "o3", "o4", \
+ "o5" \
+ );
+
+#else /* __sparc64__ */
+
+#define MULADDC_INIT \
+ asm( \
+ "ld %3, %%o0 \n\t" \
+ "ld %4, %%o1 \n\t" \
+ "ld %5, %%o2 \n\t" \
+ "ld %6, %%o3 \n\t"
+
+#define MULADDC_CORE \
+ "ld [%%o0], %%o4 \n\t" \
+ "inc 4, %%o0 \n\t" \
+ "ld [%%o1], %%o5 \n\t" \
+ "umul %%o3, %%o4, %%o4 \n\t" \
+ "addcc %%o4, %%o2, %%o4 \n\t" \
+ "rd %%y, %%g1 \n\t" \
+ "addx %%g1, 0, %%g1 \n\t" \
+ "addcc %%o4, %%o5, %%o4 \n\t" \
+ "st %%o4, [%%o1] \n\t" \
+ "addx %%g1, 0, %%o2 \n\t" \
+ "inc 4, %%o1 \n\t"
+
+#define MULADDC_STOP \
+ "st %%o2, %0 \n\t" \
+ "st %%o1, %1 \n\t" \
+ "st %%o0, %2 \n\t" \
+ : "=m" (c), "=m" (d), "=m" (s) \
+ : "m" (s), "m" (d), "m" (c), "m" (b) \
+ : "g1", "o0", "o1", "o2", "o3", "o4", \
+ "o5" \
+ );
+
+#endif /* __sparc64__ */
+#endif /* __sparc__ */
+
+#if defined(__microblaze__) || defined(microblaze)
+
+#define MULADDC_INIT \
+ asm( \
+ "lwi r3, %3 \n\t" \
+ "lwi r4, %4 \n\t" \
+ "lwi r5, %5 \n\t" \
+ "lwi r6, %6 \n\t" \
+ "andi r7, r6, 0xffff \n\t" \
+ "bsrli r6, r6, 16 \n\t"
+
+#define MULADDC_CORE \
+ "lhui r8, r3, 0 \n\t" \
+ "addi r3, r3, 2 \n\t" \
+ "lhui r9, r3, 0 \n\t" \
+ "addi r3, r3, 2 \n\t" \
+ "mul r10, r9, r6 \n\t" \
+ "mul r11, r8, r7 \n\t" \
+ "mul r12, r9, r7 \n\t" \
+ "mul r13, r8, r6 \n\t" \
+ "bsrli r8, r10, 16 \n\t" \
+ "bsrli r9, r11, 16 \n\t" \
+ "add r13, r13, r8 \n\t" \
+ "add r13, r13, r9 \n\t" \
+ "bslli r10, r10, 16 \n\t" \
+ "bslli r11, r11, 16 \n\t" \
+ "add r12, r12, r10 \n\t" \
+ "addc r13, r13, r0 \n\t" \
+ "add r12, r12, r11 \n\t" \
+ "addc r13, r13, r0 \n\t" \
+ "lwi r10, r4, 0 \n\t" \
+ "add r12, r12, r10 \n\t" \
+ "addc r13, r13, r0 \n\t" \
+ "add r12, r12, r5 \n\t" \
+ "addc r5, r13, r0 \n\t" \
+ "swi r12, r4, 0 \n\t" \
+ "addi r4, r4, 4 \n\t"
+
+#define MULADDC_STOP \
+ "swi r5, %0 \n\t" \
+ "swi r4, %1 \n\t" \
+ "swi r3, %2 \n\t" \
+ : "=m" (c), "=m" (d), "=m" (s) \
+ : "m" (s), "m" (d), "m" (c), "m" (b) \
+ : "r3", "r4" "r5", "r6", "r7", "r8", \
+ "r9", "r10", "r11", "r12", "r13" \
+ );
+
+#endif /* MicroBlaze */
+
+#if defined(__tricore__)
+
+#define MULADDC_INIT \
+ asm( \
+ "ld.a %%a2, %3 \n\t" \
+ "ld.a %%a3, %4 \n\t" \
+ "ld.w %%d4, %5 \n\t" \
+ "ld.w %%d1, %6 \n\t" \
+ "xor %%d5, %%d5 \n\t"
+
+#define MULADDC_CORE \
+ "ld.w %%d0, [%%a2+] \n\t" \
+ "madd.u %%e2, %%e4, %%d0, %%d1 \n\t" \
+ "ld.w %%d0, [%%a3] \n\t" \
+ "addx %%d2, %%d2, %%d0 \n\t" \
+ "addc %%d3, %%d3, 0 \n\t" \
+ "mov %%d4, %%d3 \n\t" \
+ "st.w [%%a3+], %%d2 \n\t"
+
+#define MULADDC_STOP \
+ "st.w %0, %%d4 \n\t" \
+ "st.a %1, %%a3 \n\t" \
+ "st.a %2, %%a2 \n\t" \
+ : "=m" (c), "=m" (d), "=m" (s) \
+ : "m" (s), "m" (d), "m" (c), "m" (b) \
+ : "d0", "d1", "e2", "d4", "a2", "a3" \
+ );
+
+#endif /* TriCore */
+
+/*
+ * gcc -O0 by default uses r7 for the frame pointer, so it complains about our
+ * use of r7 below, unless -fomit-frame-pointer is passed. Unfortunately,
+ * passing that option is not easy when building with yotta.
+ *
+ * On the other hand, -fomit-frame-pointer is implied by any -Ox options with
+ * x !=0, which we can detect using __OPTIMIZE__ (which is also defined by
+ * clang and armcc5 under the same conditions).
+ *
+ * So, only use the optimized assembly below for optimized build, which avoids
+ * the build error and is pretty reasonable anyway.
+ */
+#if defined(__GNUC__) && !defined(__OPTIMIZE__)
+#define MULADDC_CANNOT_USE_R7
+#endif
+
+#if defined(__arm__) && !defined(MULADDC_CANNOT_USE_R7)
+
+#if defined(__thumb__) && !defined(__thumb2__)
+
+#define MULADDC_INIT \
+ asm( \
+ "ldr r0, %3 \n\t" \
+ "ldr r1, %4 \n\t" \
+ "ldr r2, %5 \n\t" \
+ "ldr r3, %6 \n\t" \
+ "lsr r7, r3, #16 \n\t" \
+ "mov r9, r7 \n\t" \
+ "lsl r7, r3, #16 \n\t" \
+ "lsr r7, r7, #16 \n\t" \
+ "mov r8, r7 \n\t"
+
+#define MULADDC_CORE \
+ "ldmia r0!, {r6} \n\t" \
+ "lsr r7, r6, #16 \n\t" \
+ "lsl r6, r6, #16 \n\t" \
+ "lsr r6, r6, #16 \n\t" \
+ "mov r4, r8 \n\t" \
+ "mul r4, r6 \n\t" \
+ "mov r3, r9 \n\t" \
+ "mul r6, r3 \n\t" \
+ "mov r5, r9 \n\t" \
+ "mul r5, r7 \n\t" \
+ "mov r3, r8 \n\t" \
+ "mul r7, r3 \n\t" \
+ "lsr r3, r6, #16 \n\t" \
+ "add r5, r5, r3 \n\t" \
+ "lsr r3, r7, #16 \n\t" \
+ "add r5, r5, r3 \n\t" \
+ "add r4, r4, r2 \n\t" \
+ "mov r2, #0 \n\t" \
+ "adc r5, r2 \n\t" \
+ "lsl r3, r6, #16 \n\t" \
+ "add r4, r4, r3 \n\t" \
+ "adc r5, r2 \n\t" \
+ "lsl r3, r7, #16 \n\t" \
+ "add r4, r4, r3 \n\t" \
+ "adc r5, r2 \n\t" \
+ "ldr r3, [r1] \n\t" \
+ "add r4, r4, r3 \n\t" \
+ "adc r2, r5 \n\t" \
+ "stmia r1!, {r4} \n\t"
+
+#define MULADDC_STOP \
+ "str r2, %0 \n\t" \
+ "str r1, %1 \n\t" \
+ "str r0, %2 \n\t" \
+ : "=m" (c), "=m" (d), "=m" (s) \
+ : "m" (s), "m" (d), "m" (c), "m" (b) \
+ : "r0", "r1", "r2", "r3", "r4", "r5", \
+ "r6", "r7", "r8", "r9", "cc" \
+ );
+
+#else
+
+#define MULADDC_INIT \
+ asm( \
+ "ldr r0, %3 \n\t" \
+ "ldr r1, %4 \n\t" \
+ "ldr r2, %5 \n\t" \
+ "ldr r3, %6 \n\t"
+
+#define MULADDC_CORE \
+ "ldr r4, [r0], #4 \n\t" \
+ "mov r5, #0 \n\t" \
+ "ldr r6, [r1] \n\t" \
+ "umlal r2, r5, r3, r4 \n\t" \
+ "adds r7, r6, r2 \n\t" \
+ "adc r2, r5, #0 \n\t" \
+ "str r7, [r1], #4 \n\t"
+
+#define MULADDC_STOP \
+ "str r2, %0 \n\t" \
+ "str r1, %1 \n\t" \
+ "str r0, %2 \n\t" \
+ : "=m" (c), "=m" (d), "=m" (s) \
+ : "m" (s), "m" (d), "m" (c), "m" (b) \
+ : "r0", "r1", "r2", "r3", "r4", "r5", \
+ "r6", "r7", "cc" \
+ );
+
+#endif /* Thumb */
+
+#endif /* ARMv3 */
+
+#if defined(__alpha__)
+
+#define MULADDC_INIT \
+ asm( \
+ "ldq $1, %3 \n\t" \
+ "ldq $2, %4 \n\t" \
+ "ldq $3, %5 \n\t" \
+ "ldq $4, %6 \n\t"
+
+#define MULADDC_CORE \
+ "ldq $6, 0($1) \n\t" \
+ "addq $1, 8, $1 \n\t" \
+ "mulq $6, $4, $7 \n\t" \
+ "umulh $6, $4, $6 \n\t" \
+ "addq $7, $3, $7 \n\t" \
+ "cmpult $7, $3, $3 \n\t" \
+ "ldq $5, 0($2) \n\t" \
+ "addq $7, $5, $7 \n\t" \
+ "cmpult $7, $5, $5 \n\t" \
+ "stq $7, 0($2) \n\t" \
+ "addq $2, 8, $2 \n\t" \
+ "addq $6, $3, $3 \n\t" \
+ "addq $5, $3, $3 \n\t"
+
+#define MULADDC_STOP \
+ "stq $3, %0 \n\t" \
+ "stq $2, %1 \n\t" \
+ "stq $1, %2 \n\t" \
+ : "=m" (c), "=m" (d), "=m" (s) \
+ : "m" (s), "m" (d), "m" (c), "m" (b) \
+ : "$1", "$2", "$3", "$4", "$5", "$6", "$7" \
+ );
+#endif /* Alpha */
+
+#if defined(__mips__) && !defined(__mips64)
+
+#define MULADDC_INIT \
+ asm( \
+ "lw $10, %3 \n\t" \
+ "lw $11, %4 \n\t" \
+ "lw $12, %5 \n\t" \
+ "lw $13, %6 \n\t"
+
+#define MULADDC_CORE \
+ "lw $14, 0($10) \n\t" \
+ "multu $13, $14 \n\t" \
+ "addi $10, $10, 4 \n\t" \
+ "mflo $14 \n\t" \
+ "mfhi $9 \n\t" \
+ "addu $14, $12, $14 \n\t" \
+ "lw $15, 0($11) \n\t" \
+ "sltu $12, $14, $12 \n\t" \
+ "addu $15, $14, $15 \n\t" \
+ "sltu $14, $15, $14 \n\t" \
+ "addu $12, $12, $9 \n\t" \
+ "sw $15, 0($11) \n\t" \
+ "addu $12, $12, $14 \n\t" \
+ "addi $11, $11, 4 \n\t"
+
+#define MULADDC_STOP \
+ "sw $12, %0 \n\t" \
+ "sw $11, %1 \n\t" \
+ "sw $10, %2 \n\t" \
+ : "=m" (c), "=m" (d), "=m" (s) \
+ : "m" (s), "m" (d), "m" (c), "m" (b) \
+ : "$9", "$10", "$11", "$12", "$13", "$14", "$15" \
+ );
+
+#endif /* MIPS */
+#endif /* GNUC */
+
+#if (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
+
+#define MULADDC_INIT \
+ __asm mov esi, s \
+ __asm mov edi, d \
+ __asm mov ecx, c \
+ __asm mov ebx, b
+
+#define MULADDC_CORE \
+ __asm lodsd \
+ __asm mul ebx \
+ __asm add eax, ecx \
+ __asm adc edx, 0 \
+ __asm add eax, [edi] \
+ __asm adc edx, 0 \
+ __asm mov ecx, edx \
+ __asm stosd
+
+#if defined(MBEDTLS_HAVE_SSE2)
+
+#define EMIT __asm _emit
+
+#define MULADDC_HUIT \
+ EMIT 0x0F EMIT 0x6E EMIT 0xC9 \
+ EMIT 0x0F EMIT 0x6E EMIT 0xC3 \
+ EMIT 0x0F EMIT 0x6E EMIT 0x1F \
+ EMIT 0x0F EMIT 0xD4 EMIT 0xCB \
+ EMIT 0x0F EMIT 0x6E EMIT 0x16 \
+ EMIT 0x0F EMIT 0xF4 EMIT 0xD0 \
+ EMIT 0x0F EMIT 0x6E EMIT 0x66 EMIT 0x04 \
+ EMIT 0x0F EMIT 0xF4 EMIT 0xE0 \
+ EMIT 0x0F EMIT 0x6E EMIT 0x76 EMIT 0x08 \
+ EMIT 0x0F EMIT 0xF4 EMIT 0xF0 \
+ EMIT 0x0F EMIT 0x6E EMIT 0x7E EMIT 0x0C \
+ EMIT 0x0F EMIT 0xF4 EMIT 0xF8 \
+ EMIT 0x0F EMIT 0xD4 EMIT 0xCA \
+ EMIT 0x0F EMIT 0x6E EMIT 0x5F EMIT 0x04 \
+ EMIT 0x0F EMIT 0xD4 EMIT 0xDC \
+ EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x08 \
+ EMIT 0x0F EMIT 0xD4 EMIT 0xEE \
+ EMIT 0x0F EMIT 0x6E EMIT 0x67 EMIT 0x0C \
+ EMIT 0x0F EMIT 0xD4 EMIT 0xFC \
+ EMIT 0x0F EMIT 0x7E EMIT 0x0F \
+ EMIT 0x0F EMIT 0x6E EMIT 0x56 EMIT 0x10 \
+ EMIT 0x0F EMIT 0xF4 EMIT 0xD0 \
+ EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \
+ EMIT 0x0F EMIT 0x6E EMIT 0x66 EMIT 0x14 \
+ EMIT 0x0F EMIT 0xF4 EMIT 0xE0 \
+ EMIT 0x0F EMIT 0xD4 EMIT 0xCB \
+ EMIT 0x0F EMIT 0x6E EMIT 0x76 EMIT 0x18 \
+ EMIT 0x0F EMIT 0xF4 EMIT 0xF0 \
+ EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x04 \
+ EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \
+ EMIT 0x0F EMIT 0x6E EMIT 0x5E EMIT 0x1C \
+ EMIT 0x0F EMIT 0xF4 EMIT 0xD8 \
+ EMIT 0x0F EMIT 0xD4 EMIT 0xCD \
+ EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x10 \
+ EMIT 0x0F EMIT 0xD4 EMIT 0xD5 \
+ EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x08 \
+ EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \
+ EMIT 0x0F EMIT 0xD4 EMIT 0xCF \
+ EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x14 \
+ EMIT 0x0F EMIT 0xD4 EMIT 0xE5 \
+ EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x0C \
+ EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \
+ EMIT 0x0F EMIT 0xD4 EMIT 0xCA \
+ EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x18 \
+ EMIT 0x0F EMIT 0xD4 EMIT 0xF5 \
+ EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x10 \
+ EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \
+ EMIT 0x0F EMIT 0xD4 EMIT 0xCC \
+ EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x1C \
+ EMIT 0x0F EMIT 0xD4 EMIT 0xDD \
+ EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x14 \
+ EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \
+ EMIT 0x0F EMIT 0xD4 EMIT 0xCE \
+ EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x18 \
+ EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \
+ EMIT 0x0F EMIT 0xD4 EMIT 0xCB \
+ EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x1C \
+ EMIT 0x83 EMIT 0xC7 EMIT 0x20 \
+ EMIT 0x83 EMIT 0xC6 EMIT 0x20 \
+ EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \
+ EMIT 0x0F EMIT 0x7E EMIT 0xC9
+
+#define MULADDC_STOP \
+ EMIT 0x0F EMIT 0x77 \
+ __asm mov c, ecx \
+ __asm mov d, edi \
+ __asm mov s, esi \
+
+#else
+
+#define MULADDC_STOP \
+ __asm mov c, ecx \
+ __asm mov d, edi \
+ __asm mov s, esi \
+
+#endif /* SSE2 */
+#endif /* MSVC */
+
+#endif /* MBEDTLS_HAVE_ASM */
+
+#if !defined(MULADDC_CORE)
+#if defined(MBEDTLS_HAVE_UDBL)
+
+#define MULADDC_INIT \
+{ \
+ mbedtls_t_udbl r; \
+ mbedtls_mpi_uint r0, r1;
+
+#define MULADDC_CORE \
+ r = *(s++) * (mbedtls_t_udbl) b; \
+ r0 = (mbedtls_mpi_uint) r; \
+ r1 = (mbedtls_mpi_uint)( r >> biL ); \
+ r0 += c; r1 += (r0 < c); \
+ r0 += *d; r1 += (r0 < *d); \
+ c = r1; *(d++) = r0;
+
+#define MULADDC_STOP \
+}
+
+#else
+#define MULADDC_INIT \
+{ \
+ mbedtls_mpi_uint s0, s1, b0, b1; \
+ mbedtls_mpi_uint r0, r1, rx, ry; \
+ b0 = ( b << biH ) >> biH; \
+ b1 = ( b >> biH );
+
+#define MULADDC_CORE \
+ s0 = ( *s << biH ) >> biH; \
+ s1 = ( *s >> biH ); s++; \
+ rx = s0 * b1; r0 = s0 * b0; \
+ ry = s1 * b0; r1 = s1 * b1; \
+ r1 += ( rx >> biH ); \
+ r1 += ( ry >> biH ); \
+ rx <<= biH; ry <<= biH; \
+ r0 += rx; r1 += (r0 < rx); \
+ r0 += ry; r1 += (r0 < ry); \
+ r0 += c; r1 += (r0 < c); \
+ r0 += *d; r1 += (r0 < *d); \
+ c = r1; *(d++) = r0;
+
+#define MULADDC_STOP \
+}
+
+#endif /* C (generic) */
+#endif /* C (longlong) */
+
+#endif /* bn_mul.h */
diff --git a/backport/compat/verification/mbedtls/config.h b/backport/compat/verification/mbedtls/config.h
new file mode 100644
index 00000000..91d900de
--- /dev/null
+++ b/backport/compat/verification/mbedtls/config.h
@@ -0,0 +1,15 @@
+#ifndef __MBEDTLS_CONFIG_H
+#define __MBEDTLS_CONFIG_H
+#define MBEDTLS_RSA_C
+#define MBEDTLS_PKCS1_V15
+#define MBEDTLS_MD_C
+#define __OpenBSD__
+#define MBEDTLS_PLATFORM_C
+#define MBEDTLS_BIGNUM_C
+#define MBEDTLS_OID_C
+#define MBEDTLS_ASN1_PARSE_C
+#define MBEDTLS_NO_UDBL_DIVISION
+#define MBEDTLS_SHA256_C
+#include <linux/types.h>
+#include "platform.h"
+#endif /* __MBEDTLS_CONFIG_H */
diff --git a/backport/compat/verification/mbedtls/md.h b/backport/compat/verification/mbedtls/md.h
new file mode 100644
index 00000000..9385116c
--- /dev/null
+++ b/backport/compat/verification/mbedtls/md.h
@@ -0,0 +1,356 @@
+/**
+ * \file md.h
+ *
+ * \brief Generic message digest wrapper
+ *
+ * \author Adriaan de Jong <dejong@fox-it.com>
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: GPL-2.0
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * This file is part of mbed TLS (https://tls.mbed.org)
+ */
+#ifndef MBEDTLS_MD_H
+#define MBEDTLS_MD_H
+
+#include <stddef.h>
+
+#define MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE -0x5080 /**< The selected feature is not available. */
+#define MBEDTLS_ERR_MD_BAD_INPUT_DATA -0x5100 /**< Bad input parameters to function. */
+#define MBEDTLS_ERR_MD_ALLOC_FAILED -0x5180 /**< Failed to allocate memory. */
+#define MBEDTLS_ERR_MD_FILE_IO_ERROR -0x5200 /**< Opening or reading of file failed. */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+ MBEDTLS_MD_NONE=0,
+ MBEDTLS_MD_MD2,
+ MBEDTLS_MD_MD4,
+ MBEDTLS_MD_MD5,
+ MBEDTLS_MD_SHA1,
+ MBEDTLS_MD_SHA224,
+ MBEDTLS_MD_SHA256,
+ MBEDTLS_MD_SHA384,
+ MBEDTLS_MD_SHA512,
+ MBEDTLS_MD_RIPEMD160,
+} mbedtls_md_type_t;
+
+#if defined(MBEDTLS_SHA512_C)
+#define MBEDTLS_MD_MAX_SIZE 64 /* longest known is SHA512 */
+#else
+#define MBEDTLS_MD_MAX_SIZE 32 /* longest known is SHA256 or less */
+#endif
+
+/**
+ * Opaque struct defined in md_internal.h
+ */
+typedef struct mbedtls_md_info_t mbedtls_md_info_t;
+
+/**
+ * Generic message digest context.
+ */
+typedef struct {
+ /** Information about the associated message digest */
+ const mbedtls_md_info_t *md_info;
+
+ /** Digest-specific context */
+ void *md_ctx;
+
+ /** HMAC part of the context */
+ void *hmac_ctx;
+} mbedtls_md_context_t;
+
+/**
+ * \brief Returns the list of digests supported by the generic digest module.
+ *
+ * \return a statically allocated array of digests, the last entry
+ * is 0.
+ */
+const int *mbedtls_md_list( void );
+
+/**
+ * \brief Returns the message digest information associated with the
+ * given digest name.
+ *
+ * \param md_name Name of the digest to search for.
+ *
+ * \return The message digest information associated with md_name or
+ * NULL if not found.
+ */
+const mbedtls_md_info_t *mbedtls_md_info_from_string( const char *md_name );
+
+/**
+ * \brief Returns the message digest information associated with the
+ * given digest type.
+ *
+ * \param md_type type of digest to search for.
+ *
+ * \return The message digest information associated with md_type or
+ * NULL if not found.
+ */
+const mbedtls_md_info_t *mbedtls_md_info_from_type( mbedtls_md_type_t md_type );
+
+/**
+ * \brief Initialize a md_context (as NONE)
+ * This should always be called first.
+ * Prepares the context for mbedtls_md_setup() or mbedtls_md_free().
+ */
+void mbedtls_md_init( mbedtls_md_context_t *ctx );
+
+/**
+ * \brief Free and clear the internal structures of ctx.
+ * Can be called at any time after mbedtls_md_init().
+ * Mandatory once mbedtls_md_setup() has been called.
+ */
+void mbedtls_md_free( mbedtls_md_context_t *ctx );
+
+#if ! defined(MBEDTLS_DEPRECATED_REMOVED)
+#if defined(MBEDTLS_DEPRECATED_WARNING)
+#define MBEDTLS_DEPRECATED __attribute__((deprecated))
+#else
+#define MBEDTLS_DEPRECATED
+#endif
+/**
+ * \brief Select MD to use and allocate internal structures.
+ * Should be called after mbedtls_md_init() or mbedtls_md_free().
+ * Makes it necessary to call mbedtls_md_free() later.
+ *
+ * \deprecated Superseded by mbedtls_md_setup() in 2.0.0
+ *
+ * \param ctx Context to set up.
+ * \param md_info Message digest to use.
+ *
+ * \returns \c 0 on success,
+ * \c MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter failure,
+ * \c MBEDTLS_ERR_MD_ALLOC_FAILED memory allocation failure.
+ */
+int mbedtls_md_init_ctx( mbedtls_md_context_t *ctx, const mbedtls_md_info_t *md_info ) MBEDTLS_DEPRECATED;
+#undef MBEDTLS_DEPRECATED
+#endif /* MBEDTLS_DEPRECATED_REMOVED */
+
+/**
+ * \brief Select MD to use and allocate internal structures.
+ * Should be called after mbedtls_md_init() or mbedtls_md_free().
+ * Makes it necessary to call mbedtls_md_free() later.
+ *
+ * \param ctx Context to set up.
+ * \param md_info Message digest to use.
+ * \param hmac 0 to save some memory if HMAC will not be used,
+ * non-zero is HMAC is going to be used with this context.
+ *
+ * \returns \c 0 on success,
+ * \c MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter failure,
+ * \c MBEDTLS_ERR_MD_ALLOC_FAILED memory allocation failure.
+ */
+int mbedtls_md_setup( mbedtls_md_context_t *ctx, const mbedtls_md_info_t *md_info, int hmac );
+
+/**
+ * \brief Clone the state of an MD context
+ *
+ * \note The two contexts must have been setup to the same type
+ * (cloning from SHA-256 to SHA-512 make no sense).
+ *
+ * \warning Only clones the MD state, not the HMAC state! (for now)
+ *
+ * \param dst The destination context
+ * \param src The context to be cloned
+ *
+ * \return \c 0 on success,
+ * \c MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter failure.
+ */
+int mbedtls_md_clone( mbedtls_md_context_t *dst,
+ const mbedtls_md_context_t *src );
+
+/**
+ * \brief Returns the size of the message digest output.
+ *
+ * \param md_info message digest info
+ *
+ * \return size of the message digest output in bytes.
+ */
+unsigned char mbedtls_md_get_size( const mbedtls_md_info_t *md_info );
+
+/**
+ * \brief Returns the type of the message digest output.
+ *
+ * \param md_info message digest info
+ *
+ * \return type of the message digest output.
+ */
+mbedtls_md_type_t mbedtls_md_get_type( const mbedtls_md_info_t *md_info );
+
+/**
+ * \brief Returns the name of the message digest output.
+ *
+ * \param md_info message digest info
+ *
+ * \return name of the message digest output.
+ */
+const char *mbedtls_md_get_name( const mbedtls_md_info_t *md_info );
+
+/**
+ * \brief Prepare the context to digest a new message.
+ * Generally called after mbedtls_md_setup() or mbedtls_md_finish().
+ * Followed by mbedtls_md_update().
+ *
+ * \param ctx generic message digest context.
+ *
+ * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter
+ * verification fails.
+ */
+int mbedtls_md_starts( mbedtls_md_context_t *ctx );
+
+/**
+ * \brief Generic message digest process buffer
+ * Called between mbedtls_md_starts() and mbedtls_md_finish().
+ * May be called repeatedly.
+ *
+ * \param ctx Generic message digest context
+ * \param input buffer holding the datal
+ * \param ilen length of the input data
+ *
+ * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter
+ * verification fails.
+ */
+int mbedtls_md_update( mbedtls_md_context_t *ctx, const unsigned char *input, size_t ilen );
+
+/**
+ * \brief Generic message digest final digest
+ * Called after mbedtls_md_update().
+ * Usually followed by mbedtls_md_free() or mbedtls_md_starts().
+ *
+ * \param ctx Generic message digest context
+ * \param output Generic message digest checksum result
+ *
+ * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter
+ * verification fails.
+ */
+int mbedtls_md_finish( mbedtls_md_context_t *ctx, unsigned char *output );
+
+/**
+ * \brief Output = message_digest( input buffer )
+ *
+ * \param md_info message digest info
+ * \param input buffer holding the data
+ * \param ilen length of the input data
+ * \param output Generic message digest checksum result
+ *
+ * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter
+ * verification fails.
+ */
+int mbedtls_md( const mbedtls_md_info_t *md_info, const unsigned char *input, size_t ilen,
+ unsigned char *output );
+
+#if defined(MBEDTLS_FS_IO)
+/**
+ * \brief Output = message_digest( file contents )
+ *
+ * \param md_info message digest info
+ * \param path input file name
+ * \param output generic message digest checksum result
+ *
+ * \return 0 if successful,
+ * MBEDTLS_ERR_MD_FILE_IO_ERROR if file input failed,
+ * MBEDTLS_ERR_MD_BAD_INPUT_DATA if md_info was NULL.
+ */
+int mbedtls_md_file( const mbedtls_md_info_t *md_info, const char *path,
+ unsigned char *output );
+#endif /* MBEDTLS_FS_IO */
+
+/**
+ * \brief Set HMAC key and prepare to authenticate a new message.
+ * Usually called after mbedtls_md_setup() or mbedtls_md_hmac_finish().
+ *
+ * \param ctx HMAC context
+ * \param key HMAC secret key
+ * \param keylen length of the HMAC key in bytes
+ *
+ * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter
+ * verification fails.
+ */
+int mbedtls_md_hmac_starts( mbedtls_md_context_t *ctx, const unsigned char *key,
+ size_t keylen );
+
+/**
+ * \brief Generic HMAC process buffer.
+ * Called between mbedtls_md_hmac_starts() or mbedtls_md_hmac_reset()
+ * and mbedtls_md_hmac_finish().
+ * May be called repeatedly.
+ *
+ * \param ctx HMAC context
+ * \param input buffer holding the data
+ * \param ilen length of the input data
+ *
+ * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter
+ * verification fails.
+ */
+int mbedtls_md_hmac_update( mbedtls_md_context_t *ctx, const unsigned char *input,
+ size_t ilen );
+
+/**
+ * \brief Output HMAC.
+ * Called after mbedtls_md_hmac_update().
+ * Usually followed by mbedtls_md_hmac_reset(),
+ * mbedtls_md_hmac_starts(), or mbedtls_md_free().
+ *
+ * \param ctx HMAC context
+ * \param output Generic HMAC checksum result
+ *
+ * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter
+ * verification fails.
+ */
+int mbedtls_md_hmac_finish( mbedtls_md_context_t *ctx, unsigned char *output);
+
+/**
+ * \brief Prepare to authenticate a new message with the same key.
+ * Called after mbedtls_md_hmac_finish() and before
+ * mbedtls_md_hmac_update().
+ *
+ * \param ctx HMAC context to be reset
+ *
+ * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter
+ * verification fails.
+ */
+int mbedtls_md_hmac_reset( mbedtls_md_context_t *ctx );
+
+/**
+ * \brief Output = Generic_HMAC( hmac key, input buffer )
+ *
+ * \param md_info message digest info
+ * \param key HMAC secret key
+ * \param keylen length of the HMAC key in bytes
+ * \param input buffer holding the data
+ * \param ilen length of the input data
+ * \param output Generic HMAC-result
+ *
+ * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter
+ * verification fails.
+ */
+int mbedtls_md_hmac( const mbedtls_md_info_t *md_info, const unsigned char *key, size_t keylen,
+ const unsigned char *input, size_t ilen,
+ unsigned char *output );
+
+/* Internal use */
+int mbedtls_md_process( mbedtls_md_context_t *ctx, const unsigned char *data );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MBEDTLS_MD_H */
diff --git a/backport/compat/verification/mbedtls/md_internal.h b/backport/compat/verification/mbedtls/md_internal.h
new file mode 100644
index 00000000..0a8600b4
--- /dev/null
+++ b/backport/compat/verification/mbedtls/md_internal.h
@@ -0,0 +1,116 @@
+/**
+ * \file md_internal.h
+ *
+ * \brief Message digest wrappers.
+ *
+ * \warning This in an internal header. Do not include directly.
+ *
+ * \author Adriaan de Jong <dejong@fox-it.com>
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: GPL-2.0
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * This file is part of mbed TLS (https://tls.mbed.org)
+ */
+#ifndef MBEDTLS_MD_WRAP_H
+#define MBEDTLS_MD_WRAP_H
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#include "md.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Message digest information.
+ * Allows message digest functions to be called in a generic way.
+ */
+struct mbedtls_md_info_t
+{
+ /** Digest identifier */
+ mbedtls_md_type_t type;
+
+ /** Name of the message digest */
+ const char * name;
+
+ /** Output length of the digest function in bytes */
+ int size;
+
+ /** Block length of the digest function in bytes */
+ int block_size;
+
+ /** Digest initialisation function */
+ void (*starts_func)( void *ctx );
+
+ /** Digest update function */
+ void (*update_func)( void *ctx, const unsigned char *input, size_t ilen );
+
+ /** Digest finalisation function */
+ void (*finish_func)( void *ctx, unsigned char *output );
+
+ /** Generic digest function */
+ void (*digest_func)( const unsigned char *input, size_t ilen,
+ unsigned char *output );
+
+ /** Allocate a new context */
+ void * (*ctx_alloc_func)( void );
+
+ /** Free the given context */
+ void (*ctx_free_func)( void *ctx );
+
+ /** Clone state from a context */
+ void (*clone_func)( void *dst, const void *src );
+
+ /** Internal use only */
+ void (*process_func)( void *ctx, const unsigned char *input );
+};
+
+#if defined(MBEDTLS_MD2_C)
+extern const mbedtls_md_info_t mbedtls_md2_info;
+#endif
+#if defined(MBEDTLS_MD4_C)
+extern const mbedtls_md_info_t mbedtls_md4_info;
+#endif
+#if defined(MBEDTLS_MD5_C)
+extern const mbedtls_md_info_t mbedtls_md5_info;
+#endif
+#if defined(MBEDTLS_RIPEMD160_C)
+extern const mbedtls_md_info_t mbedtls_ripemd160_info;
+#endif
+#if defined(MBEDTLS_SHA1_C)
+extern const mbedtls_md_info_t mbedtls_sha1_info;
+#endif
+#if defined(MBEDTLS_SHA256_C)
+extern const mbedtls_md_info_t mbedtls_sha224_info;
+extern const mbedtls_md_info_t mbedtls_sha256_info;
+#endif
+#if defined(MBEDTLS_SHA512_C)
+extern const mbedtls_md_info_t mbedtls_sha384_info;
+extern const mbedtls_md_info_t mbedtls_sha512_info;
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MBEDTLS_MD_WRAP_H */
diff --git a/backport/compat/verification/mbedtls/oid.h b/backport/compat/verification/mbedtls/oid.h
new file mode 100644
index 00000000..117ee475
--- /dev/null
+++ b/backport/compat/verification/mbedtls/oid.h
@@ -0,0 +1,572 @@
+/**
+ * \file oid.h
+ *
+ * \brief Object Identifier (OID) database
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: GPL-2.0
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * This file is part of mbed TLS (https://tls.mbed.org)
+ */
+#ifndef MBEDTLS_OID_H
+#define MBEDTLS_OID_H
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#include "asn1.h"
+#include "pk.h"
+
+#include <stddef.h>
+
+#if defined(MBEDTLS_CIPHER_C)
+#include "cipher.h"
+#endif
+
+#if defined(MBEDTLS_MD_C)
+#include "md.h"
+#endif
+
+#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C)
+#include "x509.h"
+#endif
+
+#define MBEDTLS_ERR_OID_NOT_FOUND -0x002E /**< OID is not found. */
+#define MBEDTLS_ERR_OID_BUF_TOO_SMALL -0x000B /**< output buffer is too small */
+
+/*
+ * Top level OID tuples
+ */
+#define MBEDTLS_OID_ISO_MEMBER_BODIES "\x2a" /* {iso(1) member-body(2)} */
+#define MBEDTLS_OID_ISO_IDENTIFIED_ORG "\x2b" /* {iso(1) identified-organization(3)} */
+#define MBEDTLS_OID_ISO_CCITT_DS "\x55" /* {joint-iso-ccitt(2) ds(5)} */
+#define MBEDTLS_OID_ISO_ITU_COUNTRY "\x60" /* {joint-iso-itu-t(2) country(16)} */
+
+/*
+ * ISO Member bodies OID parts
+ */
+#define MBEDTLS_OID_COUNTRY_US "\x86\x48" /* {us(840)} */
+#define MBEDTLS_OID_ORG_RSA_DATA_SECURITY "\x86\xf7\x0d" /* {rsadsi(113549)} */
+#define MBEDTLS_OID_RSA_COMPANY MBEDTLS_OID_ISO_MEMBER_BODIES MBEDTLS_OID_COUNTRY_US \
+ MBEDTLS_OID_ORG_RSA_DATA_SECURITY /* {iso(1) member-body(2) us(840) rsadsi(113549)} */
+#define MBEDTLS_OID_ORG_ANSI_X9_62 "\xce\x3d" /* ansi-X9-62(10045) */
+#define MBEDTLS_OID_ANSI_X9_62 MBEDTLS_OID_ISO_MEMBER_BODIES MBEDTLS_OID_COUNTRY_US \
+ MBEDTLS_OID_ORG_ANSI_X9_62
+
+/*
+ * ISO Identified organization OID parts
+ */
+#define MBEDTLS_OID_ORG_DOD "\x06" /* {dod(6)} */
+#define MBEDTLS_OID_ORG_OIW "\x0e"
+#define MBEDTLS_OID_OIW_SECSIG MBEDTLS_OID_ORG_OIW "\x03"
+#define MBEDTLS_OID_OIW_SECSIG_ALG MBEDTLS_OID_OIW_SECSIG "\x02"
+#define MBEDTLS_OID_OIW_SECSIG_SHA1 MBEDTLS_OID_OIW_SECSIG_ALG "\x1a"
+#define MBEDTLS_OID_ORG_CERTICOM "\x81\x04" /* certicom(132) */
+#define MBEDTLS_OID_CERTICOM MBEDTLS_OID_ISO_IDENTIFIED_ORG MBEDTLS_OID_ORG_CERTICOM
+#define MBEDTLS_OID_ORG_TELETRUST "\x24" /* teletrust(36) */
+#define MBEDTLS_OID_TELETRUST MBEDTLS_OID_ISO_IDENTIFIED_ORG MBEDTLS_OID_ORG_TELETRUST
+
+/*
+ * ISO ITU OID parts
+ */
+#define MBEDTLS_OID_ORGANIZATION "\x01" /* {organization(1)} */
+#define MBEDTLS_OID_ISO_ITU_US_ORG MBEDTLS_OID_ISO_ITU_COUNTRY MBEDTLS_OID_COUNTRY_US MBEDTLS_OID_ORGANIZATION /* {joint-iso-itu-t(2) country(16) us(840) organization(1)} */
+
+#define MBEDTLS_OID_ORG_GOV "\x65" /* {gov(101)} */
+#define MBEDTLS_OID_GOV MBEDTLS_OID_ISO_ITU_US_ORG MBEDTLS_OID_ORG_GOV /* {joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101)} */
+
+#define MBEDTLS_OID_ORG_NETSCAPE "\x86\xF8\x42" /* {netscape(113730)} */
+#define MBEDTLS_OID_NETSCAPE MBEDTLS_OID_ISO_ITU_US_ORG MBEDTLS_OID_ORG_NETSCAPE /* Netscape OID {joint-iso-itu-t(2) country(16) us(840) organization(1) netscape(113730)} */
+
+/* ISO arc for standard certificate and CRL extensions */
+#define MBEDTLS_OID_ID_CE MBEDTLS_OID_ISO_CCITT_DS "\x1D" /**< id-ce OBJECT IDENTIFIER ::= {joint-iso-ccitt(2) ds(5) 29} */
+
+/**
+ * Private Internet Extensions
+ * { iso(1) identified-organization(3) dod(6) internet(1)
+ * security(5) mechanisms(5) pkix(7) }
+ */
+#define MBEDTLS_OID_PKIX MBEDTLS_OID_ISO_IDENTIFIED_ORG MBEDTLS_OID_ORG_DOD "\x01\x05\x05\x07"
+
+/*
+ * Arc for standard naming attributes
+ */
+#define MBEDTLS_OID_AT MBEDTLS_OID_ISO_CCITT_DS "\x04" /**< id-at OBJECT IDENTIFIER ::= {joint-iso-ccitt(2) ds(5) 4} */
+#define MBEDTLS_OID_AT_CN MBEDTLS_OID_AT "\x03" /**< id-at-commonName AttributeType:= {id-at 3} */
+#define MBEDTLS_OID_AT_SUR_NAME MBEDTLS_OID_AT "\x04" /**< id-at-surName AttributeType:= {id-at 4} */
+#define MBEDTLS_OID_AT_SERIAL_NUMBER MBEDTLS_OID_AT "\x05" /**< id-at-serialNumber AttributeType:= {id-at 5} */
+#define MBEDTLS_OID_AT_COUNTRY MBEDTLS_OID_AT "\x06" /**< id-at-countryName AttributeType:= {id-at 6} */
+#define MBEDTLS_OID_AT_LOCALITY MBEDTLS_OID_AT "\x07" /**< id-at-locality AttributeType:= {id-at 7} */
+#define MBEDTLS_OID_AT_STATE MBEDTLS_OID_AT "\x08" /**< id-at-state AttributeType:= {id-at 8} */
+#define MBEDTLS_OID_AT_ORGANIZATION MBEDTLS_OID_AT "\x0A" /**< id-at-organizationName AttributeType:= {id-at 10} */
+#define MBEDTLS_OID_AT_ORG_UNIT MBEDTLS_OID_AT "\x0B" /**< id-at-organizationalUnitName AttributeType:= {id-at 11} */
+#define MBEDTLS_OID_AT_TITLE MBEDTLS_OID_AT "\x0C" /**< id-at-title AttributeType:= {id-at 12} */
+#define MBEDTLS_OID_AT_POSTAL_ADDRESS MBEDTLS_OID_AT "\x10" /**< id-at-postalAddress AttributeType:= {id-at 16} */
+#define MBEDTLS_OID_AT_POSTAL_CODE MBEDTLS_OID_AT "\x11" /**< id-at-postalCode AttributeType:= {id-at 17} */
+#define MBEDTLS_OID_AT_GIVEN_NAME MBEDTLS_OID_AT "\x2A" /**< id-at-givenName AttributeType:= {id-at 42} */
+#define MBEDTLS_OID_AT_INITIALS MBEDTLS_OID_AT "\x2B" /**< id-at-initials AttributeType:= {id-at 43} */
+#define MBEDTLS_OID_AT_GENERATION_QUALIFIER MBEDTLS_OID_AT "\x2C" /**< id-at-generationQualifier AttributeType:= {id-at 44} */
+#define MBEDTLS_OID_AT_UNIQUE_IDENTIFIER MBEDTLS_OID_AT "\x2D" /**< id-at-uniqueIdentifier AttributType:= {id-at 45} */
+#define MBEDTLS_OID_AT_DN_QUALIFIER MBEDTLS_OID_AT "\x2E" /**< id-at-dnQualifier AttributeType:= {id-at 46} */
+#define MBEDTLS_OID_AT_PSEUDONYM MBEDTLS_OID_AT "\x41" /**< id-at-pseudonym AttributeType:= {id-at 65} */
+
+#define MBEDTLS_OID_DOMAIN_COMPONENT "\x09\x92\x26\x89\x93\xF2\x2C\x64\x01\x19" /** id-domainComponent AttributeType:= {itu-t(0) data(9) pss(2342) ucl(19200300) pilot(100) pilotAttributeType(1) domainComponent(25)} */
+
+/*
+ * OIDs for standard certificate extensions
+ */
+#define MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER MBEDTLS_OID_ID_CE "\x23" /**< id-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::= { id-ce 35 } */
+#define MBEDTLS_OID_SUBJECT_KEY_IDENTIFIER MBEDTLS_OID_ID_CE "\x0E" /**< id-ce-subjectKeyIdentifier OBJECT IDENTIFIER ::= { id-ce 14 } */
+#define MBEDTLS_OID_KEY_USAGE MBEDTLS_OID_ID_CE "\x0F" /**< id-ce-keyUsage OBJECT IDENTIFIER ::= { id-ce 15 } */
+#define MBEDTLS_OID_CERTIFICATE_POLICIES MBEDTLS_OID_ID_CE "\x20" /**< id-ce-certificatePolicies OBJECT IDENTIFIER ::= { id-ce 32 } */
+#define MBEDTLS_OID_POLICY_MAPPINGS MBEDTLS_OID_ID_CE "\x21" /**< id-ce-policyMappings OBJECT IDENTIFIER ::= { id-ce 33 } */
+#define MBEDTLS_OID_SUBJECT_ALT_NAME MBEDTLS_OID_ID_CE "\x11" /**< id-ce-subjectAltName OBJECT IDENTIFIER ::= { id-ce 17 } */
+#define MBEDTLS_OID_ISSUER_ALT_NAME MBEDTLS_OID_ID_CE "\x12" /**< id-ce-issuerAltName OBJECT IDENTIFIER ::= { id-ce 18 } */
+#define MBEDTLS_OID_SUBJECT_DIRECTORY_ATTRS MBEDTLS_OID_ID_CE "\x09" /**< id-ce-subjectDirectoryAttributes OBJECT IDENTIFIER ::= { id-ce 9 } */
+#define MBEDTLS_OID_BASIC_CONSTRAINTS MBEDTLS_OID_ID_CE "\x13" /**< id-ce-basicConstraints OBJECT IDENTIFIER ::= { id-ce 19 } */
+#define MBEDTLS_OID_NAME_CONSTRAINTS MBEDTLS_OID_ID_CE "\x1E" /**< id-ce-nameConstraints OBJECT IDENTIFIER ::= { id-ce 30 } */
+#define MBEDTLS_OID_POLICY_CONSTRAINTS MBEDTLS_OID_ID_CE "\x24" /**< id-ce-policyConstraints OBJECT IDENTIFIER ::= { id-ce 36 } */
+#define MBEDTLS_OID_EXTENDED_KEY_USAGE MBEDTLS_OID_ID_CE "\x25" /**< id-ce-extKeyUsage OBJECT IDENTIFIER ::= { id-ce 37 } */
+#define MBEDTLS_OID_CRL_DISTRIBUTION_POINTS MBEDTLS_OID_ID_CE "\x1F" /**< id-ce-cRLDistributionPoints OBJECT IDENTIFIER ::= { id-ce 31 } */
+#define MBEDTLS_OID_INIHIBIT_ANYPOLICY MBEDTLS_OID_ID_CE "\x36" /**< id-ce-inhibitAnyPolicy OBJECT IDENTIFIER ::= { id-ce 54 } */
+#define MBEDTLS_OID_FRESHEST_CRL MBEDTLS_OID_ID_CE "\x2E" /**< id-ce-freshestCRL OBJECT IDENTIFIER ::= { id-ce 46 } */
+
+/*
+ * Netscape certificate extensions
+ */
+#define MBEDTLS_OID_NS_CERT MBEDTLS_OID_NETSCAPE "\x01"
+#define MBEDTLS_OID_NS_CERT_TYPE MBEDTLS_OID_NS_CERT "\x01"
+#define MBEDTLS_OID_NS_BASE_URL MBEDTLS_OID_NS_CERT "\x02"
+#define MBEDTLS_OID_NS_REVOCATION_URL MBEDTLS_OID_NS_CERT "\x03"
+#define MBEDTLS_OID_NS_CA_REVOCATION_URL MBEDTLS_OID_NS_CERT "\x04"
+#define MBEDTLS_OID_NS_RENEWAL_URL MBEDTLS_OID_NS_CERT "\x07"
+#define MBEDTLS_OID_NS_CA_POLICY_URL MBEDTLS_OID_NS_CERT "\x08"
+#define MBEDTLS_OID_NS_SSL_SERVER_NAME MBEDTLS_OID_NS_CERT "\x0C"
+#define MBEDTLS_OID_NS_COMMENT MBEDTLS_OID_NS_CERT "\x0D"
+#define MBEDTLS_OID_NS_DATA_TYPE MBEDTLS_OID_NETSCAPE "\x02"
+#define MBEDTLS_OID_NS_CERT_SEQUENCE MBEDTLS_OID_NS_DATA_TYPE "\x05"
+
+/*
+ * OIDs for CRL extensions
+ */
+#define MBEDTLS_OID_PRIVATE_KEY_USAGE_PERIOD MBEDTLS_OID_ID_CE "\x10"
+#define MBEDTLS_OID_CRL_NUMBER MBEDTLS_OID_ID_CE "\x14" /**< id-ce-cRLNumber OBJECT IDENTIFIER ::= { id-ce 20 } */
+
+/*
+ * X.509 v3 Extended key usage OIDs
+ */
+#define MBEDTLS_OID_ANY_EXTENDED_KEY_USAGE MBEDTLS_OID_EXTENDED_KEY_USAGE "\x00" /**< anyExtendedKeyUsage OBJECT IDENTIFIER ::= { id-ce-extKeyUsage 0 } */
+
+#define MBEDTLS_OID_KP MBEDTLS_OID_PKIX "\x03" /**< id-kp OBJECT IDENTIFIER ::= { id-pkix 3 } */
+#define MBEDTLS_OID_SERVER_AUTH MBEDTLS_OID_KP "\x01" /**< id-kp-serverAuth OBJECT IDENTIFIER ::= { id-kp 1 } */
+#define MBEDTLS_OID_CLIENT_AUTH MBEDTLS_OID_KP "\x02" /**< id-kp-clientAuth OBJECT IDENTIFIER ::= { id-kp 2 } */
+#define MBEDTLS_OID_CODE_SIGNING MBEDTLS_OID_KP "\x03" /**< id-kp-codeSigning OBJECT IDENTIFIER ::= { id-kp 3 } */
+#define MBEDTLS_OID_EMAIL_PROTECTION MBEDTLS_OID_KP "\x04" /**< id-kp-emailProtection OBJECT IDENTIFIER ::= { id-kp 4 } */
+#define MBEDTLS_OID_TIME_STAMPING MBEDTLS_OID_KP "\x08" /**< id-kp-timeStamping OBJECT IDENTIFIER ::= { id-kp 8 } */
+#define MBEDTLS_OID_OCSP_SIGNING MBEDTLS_OID_KP "\x09" /**< id-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-kp 9 } */
+
+/*
+ * PKCS definition OIDs
+ */
+
+#define MBEDTLS_OID_PKCS MBEDTLS_OID_RSA_COMPANY "\x01" /**< pkcs OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) 1 } */
+#define MBEDTLS_OID_PKCS1 MBEDTLS_OID_PKCS "\x01" /**< pkcs-1 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 } */
+#define MBEDTLS_OID_PKCS5 MBEDTLS_OID_PKCS "\x05" /**< pkcs-5 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 5 } */
+#define MBEDTLS_OID_PKCS9 MBEDTLS_OID_PKCS "\x09" /**< pkcs-9 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 9 } */
+#define MBEDTLS_OID_PKCS12 MBEDTLS_OID_PKCS "\x0c" /**< pkcs-12 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 12 } */
+
+/*
+ * PKCS#1 OIDs
+ */
+#define MBEDTLS_OID_PKCS1_RSA MBEDTLS_OID_PKCS1 "\x01" /**< rsaEncryption OBJECT IDENTIFIER ::= { pkcs-1 1 } */
+#define MBEDTLS_OID_PKCS1_MD2 MBEDTLS_OID_PKCS1 "\x02" /**< md2WithRSAEncryption ::= { pkcs-1 2 } */
+#define MBEDTLS_OID_PKCS1_MD4 MBEDTLS_OID_PKCS1 "\x03" /**< md4WithRSAEncryption ::= { pkcs-1 3 } */
+#define MBEDTLS_OID_PKCS1_MD5 MBEDTLS_OID_PKCS1 "\x04" /**< md5WithRSAEncryption ::= { pkcs-1 4 } */
+#define MBEDTLS_OID_PKCS1_SHA1 MBEDTLS_OID_PKCS1 "\x05" /**< sha1WithRSAEncryption ::= { pkcs-1 5 } */
+#define MBEDTLS_OID_PKCS1_SHA224 MBEDTLS_OID_PKCS1 "\x0e" /**< sha224WithRSAEncryption ::= { pkcs-1 14 } */
+#define MBEDTLS_OID_PKCS1_SHA256 MBEDTLS_OID_PKCS1 "\x0b" /**< sha256WithRSAEncryption ::= { pkcs-1 11 } */
+#define MBEDTLS_OID_PKCS1_SHA384 MBEDTLS_OID_PKCS1 "\x0c" /**< sha384WithRSAEncryption ::= { pkcs-1 12 } */
+#define MBEDTLS_OID_PKCS1_SHA512 MBEDTLS_OID_PKCS1 "\x0d" /**< sha512WithRSAEncryption ::= { pkcs-1 13 } */
+
+#define MBEDTLS_OID_RSA_SHA_OBS "\x2B\x0E\x03\x02\x1D"
+
+#define MBEDTLS_OID_PKCS9_EMAIL MBEDTLS_OID_PKCS9 "\x01" /**< emailAddress AttributeType ::= { pkcs-9 1 } */
+
+/* RFC 4055 */
+#define MBEDTLS_OID_RSASSA_PSS MBEDTLS_OID_PKCS1 "\x0a" /**< id-RSASSA-PSS ::= { pkcs-1 10 } */
+#define MBEDTLS_OID_MGF1 MBEDTLS_OID_PKCS1 "\x08" /**< id-mgf1 ::= { pkcs-1 8 } */
+
+/*
+ * Digest algorithms
+ */
+#define MBEDTLS_OID_DIGEST_ALG_MD2 MBEDTLS_OID_RSA_COMPANY "\x02\x02" /**< id-mbedtls_md2 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 2 } */
+#define MBEDTLS_OID_DIGEST_ALG_MD4 MBEDTLS_OID_RSA_COMPANY "\x02\x04" /**< id-mbedtls_md4 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 4 } */
+#define MBEDTLS_OID_DIGEST_ALG_MD5 MBEDTLS_OID_RSA_COMPANY "\x02\x05" /**< id-mbedtls_md5 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 5 } */
+#define MBEDTLS_OID_DIGEST_ALG_SHA1 MBEDTLS_OID_ISO_IDENTIFIED_ORG MBEDTLS_OID_OIW_SECSIG_SHA1 /**< id-mbedtls_sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 } */
+#define MBEDTLS_OID_DIGEST_ALG_SHA224 MBEDTLS_OID_GOV "\x03\x04\x02\x04" /**< id-sha224 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistalgorithm(4) hashalgs(2) 4 } */
+#define MBEDTLS_OID_DIGEST_ALG_SHA256 MBEDTLS_OID_GOV "\x03\x04\x02\x01" /**< id-mbedtls_sha256 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistalgorithm(4) hashalgs(2) 1 } */
+
+#define MBEDTLS_OID_DIGEST_ALG_SHA384 MBEDTLS_OID_GOV "\x03\x04\x02\x02" /**< id-sha384 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistalgorithm(4) hashalgs(2) 2 } */
+
+#define MBEDTLS_OID_DIGEST_ALG_SHA512 MBEDTLS_OID_GOV "\x03\x04\x02\x03" /**< id-mbedtls_sha512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistalgorithm(4) hashalgs(2) 3 } */
+
+#define MBEDTLS_OID_HMAC_SHA1 MBEDTLS_OID_RSA_COMPANY "\x02\x07" /**< id-hmacWithSHA1 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 7 } */
+
+/*
+ * Encryption algorithms
+ */
+#define MBEDTLS_OID_DES_CBC MBEDTLS_OID_ISO_IDENTIFIED_ORG MBEDTLS_OID_OIW_SECSIG_ALG "\x07" /**< desCBC OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 7 } */
+#define MBEDTLS_OID_DES_EDE3_CBC MBEDTLS_OID_RSA_COMPANY "\x03\x07" /**< des-ede3-cbc OBJECT IDENTIFIER ::= { iso(1) member-body(2) -- us(840) rsadsi(113549) encryptionAlgorithm(3) 7 } */
+
+/*
+ * PKCS#5 OIDs
+ */
+#define MBEDTLS_OID_PKCS5_PBKDF2 MBEDTLS_OID_PKCS5 "\x0c" /**< id-PBKDF2 OBJECT IDENTIFIER ::= {pkcs-5 12} */
+#define MBEDTLS_OID_PKCS5_PBES2 MBEDTLS_OID_PKCS5 "\x0d" /**< id-PBES2 OBJECT IDENTIFIER ::= {pkcs-5 13} */
+#define MBEDTLS_OID_PKCS5_PBMAC1 MBEDTLS_OID_PKCS5 "\x0e" /**< id-PBMAC1 OBJECT IDENTIFIER ::= {pkcs-5 14} */
+
+/*
+ * PKCS#5 PBES1 algorithms
+ */
+#define MBEDTLS_OID_PKCS5_PBE_MD2_DES_CBC MBEDTLS_OID_PKCS5 "\x01" /**< pbeWithMD2AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 1} */
+#define MBEDTLS_OID_PKCS5_PBE_MD2_RC2_CBC MBEDTLS_OID_PKCS5 "\x04" /**< pbeWithMD2AndRC2-CBC OBJECT IDENTIFIER ::= {pkcs-5 4} */
+#define MBEDTLS_OID_PKCS5_PBE_MD5_DES_CBC MBEDTLS_OID_PKCS5 "\x03" /**< pbeWithMD5AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 3} */
+#define MBEDTLS_OID_PKCS5_PBE_MD5_RC2_CBC MBEDTLS_OID_PKCS5 "\x06" /**< pbeWithMD5AndRC2-CBC OBJECT IDENTIFIER ::= {pkcs-5 6} */
+#define MBEDTLS_OID_PKCS5_PBE_SHA1_DES_CBC MBEDTLS_OID_PKCS5 "\x0a" /**< pbeWithSHA1AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 10} */
+#define MBEDTLS_OID_PKCS5_PBE_SHA1_RC2_CBC MBEDTLS_OID_PKCS5 "\x0b" /**< pbeWithSHA1AndRC2-CBC OBJECT IDENTIFIER ::= {pkcs-5 11} */
+
+/*
+ * PKCS#8 OIDs
+ */
+#define MBEDTLS_OID_PKCS9_CSR_EXT_REQ MBEDTLS_OID_PKCS9 "\x0e" /**< extensionRequest OBJECT IDENTIFIER ::= {pkcs-9 14} */
+
+/*
+ * PKCS#12 PBE OIDs
+ */
+#define MBEDTLS_OID_PKCS12_PBE MBEDTLS_OID_PKCS12 "\x01" /**< pkcs-12PbeIds OBJECT IDENTIFIER ::= {pkcs-12 1} */
+
+#define MBEDTLS_OID_PKCS12_PBE_SHA1_RC4_128 MBEDTLS_OID_PKCS12_PBE "\x01" /**< pbeWithSHAAnd128BitRC4 OBJECT IDENTIFIER ::= {pkcs-12PbeIds 1} */
+#define MBEDTLS_OID_PKCS12_PBE_SHA1_RC4_40 MBEDTLS_OID_PKCS12_PBE "\x02" /**< pbeWithSHAAnd40BitRC4 OBJECT IDENTIFIER ::= {pkcs-12PbeIds 2} */
+#define MBEDTLS_OID_PKCS12_PBE_SHA1_DES3_EDE_CBC MBEDTLS_OID_PKCS12_PBE "\x03" /**< pbeWithSHAAnd3-KeyTripleDES-CBC OBJECT IDENTIFIER ::= {pkcs-12PbeIds 3} */
+#define MBEDTLS_OID_PKCS12_PBE_SHA1_DES2_EDE_CBC MBEDTLS_OID_PKCS12_PBE "\x04" /**< pbeWithSHAAnd2-KeyTripleDES-CBC OBJECT IDENTIFIER ::= {pkcs-12PbeIds 4} */
+#define MBEDTLS_OID_PKCS12_PBE_SHA1_RC2_128_CBC MBEDTLS_OID_PKCS12_PBE "\x05" /**< pbeWithSHAAnd128BitRC2-CBC OBJECT IDENTIFIER ::= {pkcs-12PbeIds 5} */
+#define MBEDTLS_OID_PKCS12_PBE_SHA1_RC2_40_CBC MBEDTLS_OID_PKCS12_PBE "\x06" /**< pbeWithSHAAnd40BitRC2-CBC OBJECT IDENTIFIER ::= {pkcs-12PbeIds 6} */
+
+/*
+ * EC key algorithms from RFC 5480
+ */
+
+/* id-ecPublicKey OBJECT IDENTIFIER ::= {
+ * iso(1) member-body(2) us(840) ansi-X9-62(10045) keyType(2) 1 } */
+#define MBEDTLS_OID_EC_ALG_UNRESTRICTED MBEDTLS_OID_ANSI_X9_62 "\x02\01"
+
+/* id-ecDH OBJECT IDENTIFIER ::= {
+ * iso(1) identified-organization(3) certicom(132)
+ * schemes(1) ecdh(12) } */
+#define MBEDTLS_OID_EC_ALG_ECDH MBEDTLS_OID_CERTICOM "\x01\x0c"
+
+/*
+ * ECParameters namedCurve identifiers, from RFC 5480, RFC 5639, and SEC2
+ */
+
+/* secp192r1 OBJECT IDENTIFIER ::= {
+ * iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3) prime(1) 1 } */
+#define MBEDTLS_OID_EC_GRP_SECP192R1 MBEDTLS_OID_ANSI_X9_62 "\x03\x01\x01"
+
+/* secp224r1 OBJECT IDENTIFIER ::= {
+ * iso(1) identified-organization(3) certicom(132) curve(0) 33 } */
+#define MBEDTLS_OID_EC_GRP_SECP224R1 MBEDTLS_OID_CERTICOM "\x00\x21"
+
+/* secp256r1 OBJECT IDENTIFIER ::= {
+ * iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3) prime(1) 7 } */
+#define MBEDTLS_OID_EC_GRP_SECP256R1 MBEDTLS_OID_ANSI_X9_62 "\x03\x01\x07"
+
+/* secp384r1 OBJECT IDENTIFIER ::= {
+ * iso(1) identified-organization(3) certicom(132) curve(0) 34 } */
+#define MBEDTLS_OID_EC_GRP_SECP384R1 MBEDTLS_OID_CERTICOM "\x00\x22"
+
+/* secp521r1 OBJECT IDENTIFIER ::= {
+ * iso(1) identified-organization(3) certicom(132) curve(0) 35 } */
+#define MBEDTLS_OID_EC_GRP_SECP521R1 MBEDTLS_OID_CERTICOM "\x00\x23"
+
+/* secp192k1 OBJECT IDENTIFIER ::= {
+ * iso(1) identified-organization(3) certicom(132) curve(0) 31 } */
+#define MBEDTLS_OID_EC_GRP_SECP192K1 MBEDTLS_OID_CERTICOM "\x00\x1f"
+
+/* secp224k1 OBJECT IDENTIFIER ::= {
+ * iso(1) identified-organization(3) certicom(132) curve(0) 32 } */
+#define MBEDTLS_OID_EC_GRP_SECP224K1 MBEDTLS_OID_CERTICOM "\x00\x20"
+
+/* secp256k1 OBJECT IDENTIFIER ::= {
+ * iso(1) identified-organization(3) certicom(132) curve(0) 10 } */
+#define MBEDTLS_OID_EC_GRP_SECP256K1 MBEDTLS_OID_CERTICOM "\x00\x0a"
+
+/* RFC 5639 4.1
+ * ecStdCurvesAndGeneration OBJECT IDENTIFIER::= {iso(1)
+ * identified-organization(3) teletrust(36) algorithm(3) signature-
+ * algorithm(3) ecSign(2) 8}
+ * ellipticCurve OBJECT IDENTIFIER ::= {ecStdCurvesAndGeneration 1}
+ * versionOne OBJECT IDENTIFIER ::= {ellipticCurve 1} */
+#define MBEDTLS_OID_EC_BRAINPOOL_V1 MBEDTLS_OID_TELETRUST "\x03\x03\x02\x08\x01\x01"
+
+/* brainpoolP256r1 OBJECT IDENTIFIER ::= {versionOne 7} */
+#define MBEDTLS_OID_EC_GRP_BP256R1 MBEDTLS_OID_EC_BRAINPOOL_V1 "\x07"
+
+/* brainpoolP384r1 OBJECT IDENTIFIER ::= {versionOne 11} */
+#define MBEDTLS_OID_EC_GRP_BP384R1 MBEDTLS_OID_EC_BRAINPOOL_V1 "\x0B"
+
+/* brainpoolP512r1 OBJECT IDENTIFIER ::= {versionOne 13} */
+#define MBEDTLS_OID_EC_GRP_BP512R1 MBEDTLS_OID_EC_BRAINPOOL_V1 "\x0D"
+
+/*
+ * SEC1 C.1
+ *
+ * prime-field OBJECT IDENTIFIER ::= { id-fieldType 1 }
+ * id-fieldType OBJECT IDENTIFIER ::= { ansi-X9-62 fieldType(1)}
+ */
+#define MBEDTLS_OID_ANSI_X9_62_FIELD_TYPE MBEDTLS_OID_ANSI_X9_62 "\x01"
+#define MBEDTLS_OID_ANSI_X9_62_PRIME_FIELD MBEDTLS_OID_ANSI_X9_62_FIELD_TYPE "\x01"
+
+/*
+ * ECDSA signature identifiers, from RFC 5480
+ */
+#define MBEDTLS_OID_ANSI_X9_62_SIG MBEDTLS_OID_ANSI_X9_62 "\x04" /* signatures(4) */
+#define MBEDTLS_OID_ANSI_X9_62_SIG_SHA2 MBEDTLS_OID_ANSI_X9_62_SIG "\x03" /* ecdsa-with-SHA2(3) */
+
+/* ecdsa-with-SHA1 OBJECT IDENTIFIER ::= {
+ * iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4) 1 } */
+#define MBEDTLS_OID_ECDSA_SHA1 MBEDTLS_OID_ANSI_X9_62_SIG "\x01"
+
+/* ecdsa-with-SHA224 OBJECT IDENTIFIER ::= {
+ * iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4)
+ * ecdsa-with-SHA2(3) 1 } */
+#define MBEDTLS_OID_ECDSA_SHA224 MBEDTLS_OID_ANSI_X9_62_SIG_SHA2 "\x01"
+
+/* ecdsa-with-SHA256 OBJECT IDENTIFIER ::= {
+ * iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4)
+ * ecdsa-with-SHA2(3) 2 } */
+#define MBEDTLS_OID_ECDSA_SHA256 MBEDTLS_OID_ANSI_X9_62_SIG_SHA2 "\x02"
+
+/* ecdsa-with-SHA384 OBJECT IDENTIFIER ::= {
+ * iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4)
+ * ecdsa-with-SHA2(3) 3 } */
+#define MBEDTLS_OID_ECDSA_SHA384 MBEDTLS_OID_ANSI_X9_62_SIG_SHA2 "\x03"
+
+/* ecdsa-with-SHA512 OBJECT IDENTIFIER ::= {
+ * iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4)
+ * ecdsa-with-SHA2(3) 4 } */
+#define MBEDTLS_OID_ECDSA_SHA512 MBEDTLS_OID_ANSI_X9_62_SIG_SHA2 "\x04"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Base OID descriptor structure
+ */
+typedef struct {
+ const char *asn1; /*!< OID ASN.1 representation */
+ size_t asn1_len; /*!< length of asn1 */
+ const char *name; /*!< official name (e.g. from RFC) */
+ const char *description; /*!< human friendly description */
+} mbedtls_oid_descriptor_t;
+
+/**
+ * \brief Translate an ASN.1 OID into its numeric representation
+ * (e.g. "\x2A\x86\x48\x86\xF7\x0D" into "1.2.840.113549")
+ *
+ * \param buf buffer to put representation in
+ * \param size size of the buffer
+ * \param oid OID to translate
+ *
+ * \return Length of the string written (excluding final NULL) or
+ * MBEDTLS_ERR_OID_BUF_TOO_SMALL in case of error
+ */
+int mbedtls_oid_get_numeric_string( char *buf, size_t size, const mbedtls_asn1_buf *oid );
+
+#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C)
+/**
+ * \brief Translate an X.509 extension OID into local values
+ *
+ * \param oid OID to use
+ * \param ext_type place to store the extension type
+ *
+ * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND
+ */
+int mbedtls_oid_get_x509_ext_type( const mbedtls_asn1_buf *oid, int *ext_type );
+#endif
+
+/**
+ * \brief Translate an X.509 attribute type OID into the short name
+ * (e.g. the OID for an X520 Common Name into "CN")
+ *
+ * \param oid OID to use
+ * \param short_name place to store the string pointer
+ *
+ * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND
+ */
+int mbedtls_oid_get_attr_short_name( const mbedtls_asn1_buf *oid, const char **short_name );
+
+/**
+ * \brief Translate PublicKeyAlgorithm OID into pk_type
+ *
+ * \param oid OID to use
+ * \param pk_alg place to store public key algorithm
+ *
+ * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND
+ */
+int mbedtls_oid_get_pk_alg( const mbedtls_asn1_buf *oid, mbedtls_pk_type_t *pk_alg );
+
+/**
+ * \brief Translate pk_type into PublicKeyAlgorithm OID
+ *
+ * \param pk_alg Public key type to look for
+ * \param oid place to store ASN.1 OID string pointer
+ * \param olen length of the OID
+ *
+ * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND
+ */
+int mbedtls_oid_get_oid_by_pk_alg( mbedtls_pk_type_t pk_alg,
+ const char **oid, size_t *olen );
+
+#if defined(MBEDTLS_ECP_C)
+/**
+ * \brief Translate NamedCurve OID into an EC group identifier
+ *
+ * \param oid OID to use
+ * \param grp_id place to store group id
+ *
+ * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND
+ */
+int mbedtls_oid_get_ec_grp( const mbedtls_asn1_buf *oid, mbedtls_ecp_group_id *grp_id );
+
+/**
+ * \brief Translate EC group identifier into NamedCurve OID
+ *
+ * \param grp_id EC group identifier
+ * \param oid place to store ASN.1 OID string pointer
+ * \param olen length of the OID
+ *
+ * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND
+ */
+int mbedtls_oid_get_oid_by_ec_grp( mbedtls_ecp_group_id grp_id,
+ const char **oid, size_t *olen );
+#endif /* MBEDTLS_ECP_C */
+
+#if defined(MBEDTLS_MD_C)
+/**
+ * \brief Translate SignatureAlgorithm OID into md_type and pk_type
+ *
+ * \param oid OID to use
+ * \param md_alg place to store message digest algorithm
+ * \param pk_alg place to store public key algorithm
+ *
+ * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND
+ */
+int mbedtls_oid_get_sig_alg( const mbedtls_asn1_buf *oid,
+ mbedtls_md_type_t *md_alg, mbedtls_pk_type_t *pk_alg );
+
+/**
+ * \brief Translate SignatureAlgorithm OID into description
+ *
+ * \param oid OID to use
+ * \param desc place to store string pointer
+ *
+ * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND
+ */
+int mbedtls_oid_get_sig_alg_desc( const mbedtls_asn1_buf *oid, const char **desc );
+
+/**
+ * \brief Translate md_type and pk_type into SignatureAlgorithm OID
+ *
+ * \param md_alg message digest algorithm
+ * \param pk_alg public key algorithm
+ * \param oid place to store ASN.1 OID string pointer
+ * \param olen length of the OID
+ *
+ * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND
+ */
+int mbedtls_oid_get_oid_by_sig_alg( mbedtls_pk_type_t pk_alg, mbedtls_md_type_t md_alg,
+ const char **oid, size_t *olen );
+
+/**
+ * \brief Translate hash algorithm OID into md_type
+ *
+ * \param oid OID to use
+ * \param md_alg place to store message digest algorithm
+ *
+ * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND
+ */
+int mbedtls_oid_get_md_alg( const mbedtls_asn1_buf *oid, mbedtls_md_type_t *md_alg );
+#endif /* MBEDTLS_MD_C */
+
+/**
+ * \brief Translate Extended Key Usage OID into description
+ *
+ * \param oid OID to use
+ * \param desc place to store string pointer
+ *
+ * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND
+ */
+int mbedtls_oid_get_extended_key_usage( const mbedtls_asn1_buf *oid, const char **desc );
+
+/**
+ * \brief Translate md_type into hash algorithm OID
+ *
+ * \param md_alg message digest algorithm
+ * \param oid place to store ASN.1 OID string pointer
+ * \param olen length of the OID
+ *
+ * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND
+ */
+int mbedtls_oid_get_oid_by_md( mbedtls_md_type_t md_alg, const char **oid, size_t *olen );
+
+#if defined(MBEDTLS_CIPHER_C)
+/**
+ * \brief Translate encryption algorithm OID into cipher_type
+ *
+ * \param oid OID to use
+ * \param cipher_alg place to store cipher algorithm
+ *
+ * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND
+ */
+int mbedtls_oid_get_cipher_alg( const mbedtls_asn1_buf *oid, mbedtls_cipher_type_t *cipher_alg );
+#endif /* MBEDTLS_CIPHER_C */
+
+#if defined(MBEDTLS_PKCS12_C)
+/**
+ * \brief Translate PKCS#12 PBE algorithm OID into md_type and
+ * cipher_type
+ *
+ * \param oid OID to use
+ * \param md_alg place to store message digest algorithm
+ * \param cipher_alg place to store cipher algorithm
+ *
+ * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND
+ */
+int mbedtls_oid_get_pkcs12_pbe_alg( const mbedtls_asn1_buf *oid, mbedtls_md_type_t *md_alg,
+ mbedtls_cipher_type_t *cipher_alg );
+#endif /* MBEDTLS_PKCS12_C */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* oid.h */
diff --git a/backport/compat/verification/mbedtls/pk.h b/backport/compat/verification/mbedtls/pk.h
new file mode 100644
index 00000000..9aac7e2a
--- /dev/null
+++ b/backport/compat/verification/mbedtls/pk.h
@@ -0,0 +1,618 @@
+/**
+ * \file pk.h
+ *
+ * \brief Public Key abstraction layer
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: GPL-2.0
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * This file is part of mbed TLS (https://tls.mbed.org)
+ */
+
+#ifndef MBEDTLS_PK_H
+#define MBEDTLS_PK_H
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#include "md.h"
+
+#if defined(MBEDTLS_RSA_C)
+#include "rsa.h"
+#endif
+
+#if defined(MBEDTLS_ECP_C)
+#include "ecp.h"
+#endif
+
+#if defined(MBEDTLS_ECDSA_C)
+#include "ecdsa.h"
+#endif
+
+#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \
+ !defined(inline) && !defined(__cplusplus)
+#define inline __inline
+#endif
+
+#define MBEDTLS_ERR_PK_ALLOC_FAILED -0x3F80 /**< Memory allocation failed. */
+#define MBEDTLS_ERR_PK_TYPE_MISMATCH -0x3F00 /**< Type mismatch, eg attempt to encrypt with an ECDSA key */
+#define MBEDTLS_ERR_PK_BAD_INPUT_DATA -0x3E80 /**< Bad input parameters to function. */
+#define MBEDTLS_ERR_PK_FILE_IO_ERROR -0x3E00 /**< Read/write of file failed. */
+#define MBEDTLS_ERR_PK_KEY_INVALID_VERSION -0x3D80 /**< Unsupported key version */
+#define MBEDTLS_ERR_PK_KEY_INVALID_FORMAT -0x3D00 /**< Invalid key tag or value. */
+#define MBEDTLS_ERR_PK_UNKNOWN_PK_ALG -0x3C80 /**< Key algorithm is unsupported (only RSA and EC are supported). */
+#define MBEDTLS_ERR_PK_PASSWORD_REQUIRED -0x3C00 /**< Private key password can't be empty. */
+#define MBEDTLS_ERR_PK_PASSWORD_MISMATCH -0x3B80 /**< Given private key password does not allow for correct decryption. */
+#define MBEDTLS_ERR_PK_INVALID_PUBKEY -0x3B00 /**< The pubkey tag or value is invalid (only RSA and EC are supported). */
+#define MBEDTLS_ERR_PK_INVALID_ALG -0x3A80 /**< The algorithm tag or value is invalid. */
+#define MBEDTLS_ERR_PK_UNKNOWN_NAMED_CURVE -0x3A00 /**< Elliptic curve is unsupported (only NIST curves are supported). */
+#define MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE -0x3980 /**< Unavailable feature, e.g. RSA disabled for RSA key. */
+#define MBEDTLS_ERR_PK_SIG_LEN_MISMATCH -0x3900 /**< The signature is valid but its length is less than expected. */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Public key types
+ */
+typedef enum {
+ MBEDTLS_PK_NONE=0,
+ MBEDTLS_PK_RSA,
+ MBEDTLS_PK_ECKEY,
+ MBEDTLS_PK_ECKEY_DH,
+ MBEDTLS_PK_ECDSA,
+ MBEDTLS_PK_RSA_ALT,
+ MBEDTLS_PK_RSASSA_PSS,
+} mbedtls_pk_type_t;
+
+/**
+ * \brief Options for RSASSA-PSS signature verification.
+ * See \c mbedtls_rsa_rsassa_pss_verify_ext()
+ */
+typedef struct
+{
+ mbedtls_md_type_t mgf1_hash_id;
+ int expected_salt_len;
+
+} mbedtls_pk_rsassa_pss_options;
+
+/**
+ * \brief Types for interfacing with the debug module
+ */
+typedef enum
+{
+ MBEDTLS_PK_DEBUG_NONE = 0,
+ MBEDTLS_PK_DEBUG_MPI,
+ MBEDTLS_PK_DEBUG_ECP,
+} mbedtls_pk_debug_type;
+
+/**
+ * \brief Item to send to the debug module
+ */
+typedef struct
+{
+ mbedtls_pk_debug_type type;
+ const char *name;
+ void *value;
+} mbedtls_pk_debug_item;
+
+/** Maximum number of item send for debugging, plus 1 */
+#define MBEDTLS_PK_DEBUG_MAX_ITEMS 3
+
+/**
+ * \brief Public key information and operations
+ */
+typedef struct mbedtls_pk_info_t mbedtls_pk_info_t;
+
+/**
+ * \brief Public key container
+ */
+typedef struct
+{
+ const mbedtls_pk_info_t * pk_info; /**< Public key informations */
+ void * pk_ctx; /**< Underlying public key context */
+} mbedtls_pk_context;
+
+#if defined(MBEDTLS_RSA_C)
+/**
+ * Quick access to an RSA context inside a PK context.
+ *
+ * \warning You must make sure the PK context actually holds an RSA context
+ * before using this function!
+ */
+static inline mbedtls_rsa_context *mbedtls_pk_rsa( const mbedtls_pk_context pk )
+{
+ return( (mbedtls_rsa_context *) (pk).pk_ctx );
+}
+#endif /* MBEDTLS_RSA_C */
+
+#if defined(MBEDTLS_ECP_C)
+/**
+ * Quick access to an EC context inside a PK context.
+ *
+ * \warning You must make sure the PK context actually holds an EC context
+ * before using this function!
+ */
+static inline mbedtls_ecp_keypair *mbedtls_pk_ec( const mbedtls_pk_context pk )
+{
+ return( (mbedtls_ecp_keypair *) (pk).pk_ctx );
+}
+#endif /* MBEDTLS_ECP_C */
+
+#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT)
+/**
+ * \brief Types for RSA-alt abstraction
+ */
+typedef int (*mbedtls_pk_rsa_alt_decrypt_func)( void *ctx, int mode, size_t *olen,
+ const unsigned char *input, unsigned char *output,
+ size_t output_max_len );
+typedef int (*mbedtls_pk_rsa_alt_sign_func)( void *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
+ int mode, mbedtls_md_type_t md_alg, unsigned int hashlen,
+ const unsigned char *hash, unsigned char *sig );
+typedef size_t (*mbedtls_pk_rsa_alt_key_len_func)( void *ctx );
+#endif /* MBEDTLS_PK_RSA_ALT_SUPPORT */
+
+/**
+ * \brief Return information associated with the given PK type
+ *
+ * \param pk_type PK type to search for.
+ *
+ * \return The PK info associated with the type or NULL if not found.
+ */
+const mbedtls_pk_info_t *mbedtls_pk_info_from_type( mbedtls_pk_type_t pk_type );
+
+/**
+ * \brief Initialize a mbedtls_pk_context (as NONE)
+ */
+void mbedtls_pk_init( mbedtls_pk_context *ctx );
+
+/**
+ * \brief Free a mbedtls_pk_context
+ */
+void mbedtls_pk_free( mbedtls_pk_context *ctx );
+
+/**
+ * \brief Initialize a PK context with the information given
+ * and allocates the type-specific PK subcontext.
+ *
+ * \param ctx Context to initialize. Must be empty (type NONE).
+ * \param info Information to use
+ *
+ * \return 0 on success,
+ * MBEDTLS_ERR_PK_BAD_INPUT_DATA on invalid input,
+ * MBEDTLS_ERR_PK_ALLOC_FAILED on allocation failure.
+ *
+ * \note For contexts holding an RSA-alt key, use
+ * \c mbedtls_pk_setup_rsa_alt() instead.
+ */
+int mbedtls_pk_setup( mbedtls_pk_context *ctx, const mbedtls_pk_info_t *info );
+
+#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT)
+/**
+ * \brief Initialize an RSA-alt context
+ *
+ * \param ctx Context to initialize. Must be empty (type NONE).
+ * \param key RSA key pointer
+ * \param decrypt_func Decryption function
+ * \param sign_func Signing function
+ * \param key_len_func Function returning key length in bytes
+ *
+ * \return 0 on success, or MBEDTLS_ERR_PK_BAD_INPUT_DATA if the
+ * context wasn't already initialized as RSA_ALT.
+ *
+ * \note This function replaces \c mbedtls_pk_setup() for RSA-alt.
+ */
+int mbedtls_pk_setup_rsa_alt( mbedtls_pk_context *ctx, void * key,
+ mbedtls_pk_rsa_alt_decrypt_func decrypt_func,
+ mbedtls_pk_rsa_alt_sign_func sign_func,
+ mbedtls_pk_rsa_alt_key_len_func key_len_func );
+#endif /* MBEDTLS_PK_RSA_ALT_SUPPORT */
+
+/**
+ * \brief Get the size in bits of the underlying key
+ *
+ * \param ctx Context to use
+ *
+ * \return Key size in bits, or 0 on error
+ */
+size_t mbedtls_pk_get_bitlen( const mbedtls_pk_context *ctx );
+
+/**
+ * \brief Get the length in bytes of the underlying key
+ * \param ctx Context to use
+ *
+ * \return Key length in bytes, or 0 on error
+ */
+static inline size_t mbedtls_pk_get_len( const mbedtls_pk_context *ctx )
+{
+ return( ( mbedtls_pk_get_bitlen( ctx ) + 7 ) / 8 );
+}
+
+/**
+ * \brief Tell if a context can do the operation given by type
+ *
+ * \param ctx Context to test
+ * \param type Target type
+ *
+ * \return 0 if context can't do the operations,
+ * 1 otherwise.
+ */
+int mbedtls_pk_can_do( const mbedtls_pk_context *ctx, mbedtls_pk_type_t type );
+
+/**
+ * \brief Verify signature (including padding if relevant).
+ *
+ * \param ctx PK context to use
+ * \param md_alg Hash algorithm used (see notes)
+ * \param hash Hash of the message to sign
+ * \param hash_len Hash length or 0 (see notes)
+ * \param sig Signature to verify
+ * \param sig_len Signature length
+ *
+ * \return 0 on success (signature is valid),
+ * MBEDTLS_ERR_PK_SIG_LEN_MISMATCH if the signature is
+ * valid but its actual length is less than sig_len,
+ * or a specific error code.
+ *
+ * \note For RSA keys, the default padding type is PKCS#1 v1.5.
+ * Use \c mbedtls_pk_verify_ext( MBEDTLS_PK_RSASSA_PSS, ... )
+ * to verify RSASSA_PSS signatures.
+ *
+ * \note If hash_len is 0, then the length associated with md_alg
+ * is used instead, or an error returned if it is invalid.
+ *
+ * \note md_alg may be MBEDTLS_MD_NONE, only if hash_len != 0
+ */
+int mbedtls_pk_verify( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg,
+ const unsigned char *hash, size_t hash_len,
+ const unsigned char *sig, size_t sig_len );
+
+/**
+ * \brief Verify signature, with options.
+ * (Includes verification of the padding depending on type.)
+ *
+ * \param type Signature type (inc. possible padding type) to verify
+ * \param options Pointer to type-specific options, or NULL
+ * \param ctx PK context to use
+ * \param md_alg Hash algorithm used (see notes)
+ * \param hash Hash of the message to sign
+ * \param hash_len Hash length or 0 (see notes)
+ * \param sig Signature to verify
+ * \param sig_len Signature length
+ *
+ * \return 0 on success (signature is valid),
+ * MBEDTLS_ERR_PK_TYPE_MISMATCH if the PK context can't be
+ * used for this type of signatures,
+ * MBEDTLS_ERR_PK_SIG_LEN_MISMATCH if the signature is
+ * valid but its actual length is less than sig_len,
+ * or a specific error code.
+ *
+ * \note If hash_len is 0, then the length associated with md_alg
+ * is used instead, or an error returned if it is invalid.
+ *
+ * \note md_alg may be MBEDTLS_MD_NONE, only if hash_len != 0
+ *
+ * \note If type is MBEDTLS_PK_RSASSA_PSS, then options must point
+ * to a mbedtls_pk_rsassa_pss_options structure,
+ * otherwise it must be NULL.
+ */
+int mbedtls_pk_verify_ext( mbedtls_pk_type_t type, const void *options,
+ mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg,
+ const unsigned char *hash, size_t hash_len,
+ const unsigned char *sig, size_t sig_len );
+
+/**
+ * \brief Make signature, including padding if relevant.
+ *
+ * \param ctx PK context to use - must hold a private key
+ * \param md_alg Hash algorithm used (see notes)
+ * \param hash Hash of the message to sign
+ * \param hash_len Hash length or 0 (see notes)
+ * \param sig Place to write the signature
+ * \param sig_len Number of bytes written
+ * \param f_rng RNG function
+ * \param p_rng RNG parameter
+ *
+ * \return 0 on success, or a specific error code.
+ *
+ * \note For RSA keys, the default padding type is PKCS#1 v1.5.
+ * There is no interface in the PK module to make RSASSA-PSS
+ * signatures yet.
+ *
+ * \note If hash_len is 0, then the length associated with md_alg
+ * is used instead, or an error returned if it is invalid.
+ *
+ * \note For RSA, md_alg may be MBEDTLS_MD_NONE if hash_len != 0.
+ * For ECDSA, md_alg may never be MBEDTLS_MD_NONE.
+ */
+int mbedtls_pk_sign( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg,
+ const unsigned char *hash, size_t hash_len,
+ unsigned char *sig, size_t *sig_len,
+ int (*f_rng)(void *, unsigned char *, size_t), void *p_rng );
+
+/**
+ * \brief Decrypt message (including padding if relevant).
+ *
+ * \param ctx PK context to use - must hold a private key
+ * \param input Input to decrypt
+ * \param ilen Input size
+ * \param output Decrypted output
+ * \param olen Decrypted message length
+ * \param osize Size of the output buffer
+ * \param f_rng RNG function
+ * \param p_rng RNG parameter
+ *
+ * \note For RSA keys, the default padding type is PKCS#1 v1.5.
+ *
+ * \return 0 on success, or a specific error code.
+ */
+int mbedtls_pk_decrypt( mbedtls_pk_context *ctx,
+ const unsigned char *input, size_t ilen,
+ unsigned char *output, size_t *olen, size_t osize,
+ int (*f_rng)(void *, unsigned char *, size_t), void *p_rng );
+
+/**
+ * \brief Encrypt message (including padding if relevant).
+ *
+ * \param ctx PK context to use
+ * \param input Message to encrypt
+ * \param ilen Message size
+ * \param output Encrypted output
+ * \param olen Encrypted output length
+ * \param osize Size of the output buffer
+ * \param f_rng RNG function
+ * \param p_rng RNG parameter
+ *
+ * \note For RSA keys, the default padding type is PKCS#1 v1.5.
+ *
+ * \return 0 on success, or a specific error code.
+ */
+int mbedtls_pk_encrypt( mbedtls_pk_context *ctx,
+ const unsigned char *input, size_t ilen,
+ unsigned char *output, size_t *olen, size_t osize,
+ int (*f_rng)(void *, unsigned char *, size_t), void *p_rng );
+
+/**
+ * \brief Check if a public-private pair of keys matches.
+ *
+ * \param pub Context holding a public key.
+ * \param prv Context holding a private (and public) key.
+ *
+ * \return 0 on success or MBEDTLS_ERR_PK_BAD_INPUT_DATA
+ */
+int mbedtls_pk_check_pair( const mbedtls_pk_context *pub, const mbedtls_pk_context *prv );
+
+/**
+ * \brief Export debug information
+ *
+ * \param ctx Context to use
+ * \param items Place to write debug items
+ *
+ * \return 0 on success or MBEDTLS_ERR_PK_BAD_INPUT_DATA
+ */
+int mbedtls_pk_debug( const mbedtls_pk_context *ctx, mbedtls_pk_debug_item *items );
+
+/**
+ * \brief Access the type name
+ *
+ * \param ctx Context to use
+ *
+ * \return Type name on success, or "invalid PK"
+ */
+const char * mbedtls_pk_get_name( const mbedtls_pk_context *ctx );
+
+/**
+ * \brief Get the key type
+ *
+ * \param ctx Context to use
+ *
+ * \return Type on success, or MBEDTLS_PK_NONE
+ */
+mbedtls_pk_type_t mbedtls_pk_get_type( const mbedtls_pk_context *ctx );
+
+#if defined(MBEDTLS_PK_PARSE_C)
+/** \ingroup pk_module */
+/**
+ * \brief Parse a private key in PEM or DER format
+ *
+ * \param ctx key to be initialized
+ * \param key input buffer
+ * \param keylen size of the buffer
+ * (including the terminating null byte for PEM data)
+ * \param pwd password for decryption (optional)
+ * \param pwdlen size of the password
+ *
+ * \note On entry, ctx must be empty, either freshly initialised
+ * with mbedtls_pk_init() or reset with mbedtls_pk_free(). If you need a
+ * specific key type, check the result with mbedtls_pk_can_do().
+ *
+ * \note The key is also checked for correctness.
+ *
+ * \return 0 if successful, or a specific PK or PEM error code
+ */
+int mbedtls_pk_parse_key( mbedtls_pk_context *ctx,
+ const unsigned char *key, size_t keylen,
+ const unsigned char *pwd, size_t pwdlen );
+
+/** \ingroup pk_module */
+/**
+ * \brief Parse a public key in PEM or DER format
+ *
+ * \param ctx key to be initialized
+ * \param key input buffer
+ * \param keylen size of the buffer
+ * (including the terminating null byte for PEM data)
+ *
+ * \note On entry, ctx must be empty, either freshly initialised
+ * with mbedtls_pk_init() or reset with mbedtls_pk_free(). If you need a
+ * specific key type, check the result with mbedtls_pk_can_do().
+ *
+ * \note The key is also checked for correctness.
+ *
+ * \return 0 if successful, or a specific PK or PEM error code
+ */
+int mbedtls_pk_parse_public_key( mbedtls_pk_context *ctx,
+ const unsigned char *key, size_t keylen );
+
+#if defined(MBEDTLS_FS_IO)
+/** \ingroup pk_module */
+/**
+ * \brief Load and parse a private key
+ *
+ * \param ctx key to be initialized
+ * \param path filename to read the private key from
+ * \param password password to decrypt the file (can be NULL)
+ *
+ * \note On entry, ctx must be empty, either freshly initialised
+ * with mbedtls_pk_init() or reset with mbedtls_pk_free(). If you need a
+ * specific key type, check the result with mbedtls_pk_can_do().
+ *
+ * \note The key is also checked for correctness.
+ *
+ * \return 0 if successful, or a specific PK or PEM error code
+ */
+int mbedtls_pk_parse_keyfile( mbedtls_pk_context *ctx,
+ const char *path, const char *password );
+
+/** \ingroup pk_module */
+/**
+ * \brief Load and parse a public key
+ *
+ * \param ctx key to be initialized
+ * \param path filename to read the public key from
+ *
+ * \note On entry, ctx must be empty, either freshly initialised
+ * with mbedtls_pk_init() or reset with mbedtls_pk_free(). If
+ * you need a specific key type, check the result with
+ * mbedtls_pk_can_do().
+ *
+ * \note The key is also checked for correctness.
+ *
+ * \return 0 if successful, or a specific PK or PEM error code
+ */
+int mbedtls_pk_parse_public_keyfile( mbedtls_pk_context *ctx, const char *path );
+#endif /* MBEDTLS_FS_IO */
+#endif /* MBEDTLS_PK_PARSE_C */
+
+#if defined(MBEDTLS_PK_WRITE_C)
+/**
+ * \brief Write a private key to a PKCS#1 or SEC1 DER structure
+ * Note: data is written at the end of the buffer! Use the
+ * return value to determine where you should start
+ * using the buffer
+ *
+ * \param ctx private to write away
+ * \param buf buffer to write to
+ * \param size size of the buffer
+ *
+ * \return length of data written if successful, or a specific
+ * error code
+ */
+int mbedtls_pk_write_key_der( mbedtls_pk_context *ctx, unsigned char *buf, size_t size );
+
+/**
+ * \brief Write a public key to a SubjectPublicKeyInfo DER structure
+ * Note: data is written at the end of the buffer! Use the
+ * return value to determine where you should start
+ * using the buffer
+ *
+ * \param ctx public key to write away
+ * \param buf buffer to write to
+ * \param size size of the buffer
+ *
+ * \return length of data written if successful, or a specific
+ * error code
+ */
+int mbedtls_pk_write_pubkey_der( mbedtls_pk_context *ctx, unsigned char *buf, size_t size );
+
+#if defined(MBEDTLS_PEM_WRITE_C)
+/**
+ * \brief Write a public key to a PEM string
+ *
+ * \param ctx public key to write away
+ * \param buf buffer to write to
+ * \param size size of the buffer
+ *
+ * \return 0 if successful, or a specific error code
+ */
+int mbedtls_pk_write_pubkey_pem( mbedtls_pk_context *ctx, unsigned char *buf, size_t size );
+
+/**
+ * \brief Write a private key to a PKCS#1 or SEC1 PEM string
+ *
+ * \param ctx private to write away
+ * \param buf buffer to write to
+ * \param size size of the buffer
+ *
+ * \return 0 if successful, or a specific error code
+ */
+int mbedtls_pk_write_key_pem( mbedtls_pk_context *ctx, unsigned char *buf, size_t size );
+#endif /* MBEDTLS_PEM_WRITE_C */
+#endif /* MBEDTLS_PK_WRITE_C */
+
+/*
+ * WARNING: Low-level functions. You probably do not want to use these unless
+ * you are certain you do ;)
+ */
+
+#if defined(MBEDTLS_PK_PARSE_C)
+/**
+ * \brief Parse a SubjectPublicKeyInfo DER structure
+ *
+ * \param p the position in the ASN.1 data
+ * \param end end of the buffer
+ * \param pk the key to fill
+ *
+ * \return 0 if successful, or a specific PK error code
+ */
+int mbedtls_pk_parse_subpubkey( unsigned char **p, const unsigned char *end,
+ mbedtls_pk_context *pk );
+#endif /* MBEDTLS_PK_PARSE_C */
+
+#if defined(MBEDTLS_PK_WRITE_C)
+/**
+ * \brief Write a subjectPublicKey to ASN.1 data
+ * Note: function works backwards in data buffer
+ *
+ * \param p reference to current position pointer
+ * \param start start of the buffer (for bounds-checking)
+ * \param key public key to write away
+ *
+ * \return the length written or a negative error code
+ */
+int mbedtls_pk_write_pubkey( unsigned char **p, unsigned char *start,
+ const mbedtls_pk_context *key );
+#endif /* MBEDTLS_PK_WRITE_C */
+
+/*
+ * Internal module functions. You probably do not want to use these unless you
+ * know you do.
+ */
+#if defined(MBEDTLS_FS_IO)
+int mbedtls_pk_load_file( const char *path, unsigned char **buf, size_t *n );
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MBEDTLS_PK_H */
diff --git a/backport/compat/verification/mbedtls/platform.h b/backport/compat/verification/mbedtls/platform.h
new file mode 100644
index 00000000..cf5fa56f
--- /dev/null
+++ b/backport/compat/verification/mbedtls/platform.h
@@ -0,0 +1,12 @@
+#ifndef __MBEDTLS_PLATFORM_H
+#define __MBEDTLS_PLATFORM_H
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#define mbedtls_printf pr_debug
+#define mbedtls_calloc(a, b) kcalloc(a, b, GFP_KERNEL)
+#define mbedtls_free kfree
+#define mbedtls_snprintf snprintf
+
+#endif /* __MBEDTLS_PLATFORM_H */
diff --git a/backport/compat/verification/mbedtls/rsa.h b/backport/compat/verification/mbedtls/rsa.h
new file mode 100644
index 00000000..9683520c
--- /dev/null
+++ b/backport/compat/verification/mbedtls/rsa.h
@@ -0,0 +1,672 @@
+/**
+ * \file rsa.h
+ *
+ * \brief The RSA public-key cryptosystem
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: GPL-2.0
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * This file is part of mbed TLS (https://tls.mbed.org)
+ */
+#ifndef MBEDTLS_RSA_H
+#define MBEDTLS_RSA_H
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#include "bignum.h"
+#include "md.h"
+
+#if defined(MBEDTLS_THREADING_C)
+#include "threading.h"
+#endif
+
+/*
+ * RSA Error codes
+ */
+#define MBEDTLS_ERR_RSA_BAD_INPUT_DATA -0x4080 /**< Bad input parameters to function. */
+#define MBEDTLS_ERR_RSA_INVALID_PADDING -0x4100 /**< Input data contains invalid padding and is rejected. */
+#define MBEDTLS_ERR_RSA_KEY_GEN_FAILED -0x4180 /**< Something failed during generation of a key. */
+#define MBEDTLS_ERR_RSA_KEY_CHECK_FAILED -0x4200 /**< Key failed to pass the library's validity check. */
+#define MBEDTLS_ERR_RSA_PUBLIC_FAILED -0x4280 /**< The public key operation failed. */
+#define MBEDTLS_ERR_RSA_PRIVATE_FAILED -0x4300 /**< The private key operation failed. */
+#define MBEDTLS_ERR_RSA_VERIFY_FAILED -0x4380 /**< The PKCS#1 verification failed. */
+#define MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE -0x4400 /**< The output buffer for decryption is not large enough. */
+#define MBEDTLS_ERR_RSA_RNG_FAILED -0x4480 /**< The random generator failed to generate non-zeros. */
+
+/*
+ * RSA constants
+ */
+#define MBEDTLS_RSA_PUBLIC 0
+#define MBEDTLS_RSA_PRIVATE 1
+
+#define MBEDTLS_RSA_PKCS_V15 0
+#define MBEDTLS_RSA_PKCS_V21 1
+
+#define MBEDTLS_RSA_SIGN 1
+#define MBEDTLS_RSA_CRYPT 2
+
+#define MBEDTLS_RSA_SALT_LEN_ANY -1
+
+/*
+ * The above constants may be used even if the RSA module is compile out,
+ * eg for alternative (PKCS#11) RSA implemenations in the PK layers.
+ */
+#if defined(MBEDTLS_RSA_C)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief RSA context structure
+ */
+typedef struct
+{
+ int ver; /*!< always 0 */
+ size_t len; /*!< size(N) in chars */
+
+ mbedtls_mpi N; /*!< public modulus */
+ mbedtls_mpi E; /*!< public exponent */
+
+ mbedtls_mpi D; /*!< private exponent */
+ mbedtls_mpi P; /*!< 1st prime factor */
+ mbedtls_mpi Q; /*!< 2nd prime factor */
+ mbedtls_mpi DP; /*!< D % (P - 1) */
+ mbedtls_mpi DQ; /*!< D % (Q - 1) */
+ mbedtls_mpi QP; /*!< 1 / (Q % P) */
+
+ mbedtls_mpi RN; /*!< cached R^2 mod N */
+ mbedtls_mpi RP; /*!< cached R^2 mod P */
+ mbedtls_mpi RQ; /*!< cached R^2 mod Q */
+
+ mbedtls_mpi Vi; /*!< cached blinding value */
+ mbedtls_mpi Vf; /*!< cached un-blinding value */
+
+ int padding; /*!< MBEDTLS_RSA_PKCS_V15 for 1.5 padding and
+ MBEDTLS_RSA_PKCS_v21 for OAEP/PSS */
+ int hash_id; /*!< Hash identifier of mbedtls_md_type_t as
+ specified in the mbedtls_md.h header file
+ for the EME-OAEP and EMSA-PSS
+ encoding */
+#if defined(MBEDTLS_THREADING_C)
+ mbedtls_threading_mutex_t mutex; /*!< Thread-safety mutex */
+#endif
+}
+mbedtls_rsa_context;
+
+/**
+ * \brief Initialize an RSA context
+ *
+ * Note: Set padding to MBEDTLS_RSA_PKCS_V21 for the RSAES-OAEP
+ * encryption scheme and the RSASSA-PSS signature scheme.
+ *
+ * \param ctx RSA context to be initialized
+ * \param padding MBEDTLS_RSA_PKCS_V15 or MBEDTLS_RSA_PKCS_V21
+ * \param hash_id MBEDTLS_RSA_PKCS_V21 hash identifier
+ *
+ * \note The hash_id parameter is actually ignored
+ * when using MBEDTLS_RSA_PKCS_V15 padding.
+ *
+ * \note Choice of padding mode is strictly enforced for private key
+ * operations, since there might be security concerns in
+ * mixing padding modes. For public key operations it's merely
+ * a default value, which can be overriden by calling specific
+ * rsa_rsaes_xxx or rsa_rsassa_xxx functions.
+ *
+ * \note The chosen hash is always used for OEAP encryption.
+ * For PSS signatures, it's always used for making signatures,
+ * but can be overriden (and always is, if set to
+ * MBEDTLS_MD_NONE) for verifying them.
+ */
+void mbedtls_rsa_init( mbedtls_rsa_context *ctx,
+ int padding,
+ int hash_id);
+
+/**
+ * \brief Set padding for an already initialized RSA context
+ * See \c mbedtls_rsa_init() for details.
+ *
+ * \param ctx RSA context to be set
+ * \param padding MBEDTLS_RSA_PKCS_V15 or MBEDTLS_RSA_PKCS_V21
+ * \param hash_id MBEDTLS_RSA_PKCS_V21 hash identifier
+ */
+void mbedtls_rsa_set_padding( mbedtls_rsa_context *ctx, int padding, int hash_id);
+
+/**
+ * \brief Generate an RSA keypair
+ *
+ * \param ctx RSA context that will hold the key
+ * \param f_rng RNG function
+ * \param p_rng RNG parameter
+ * \param nbits size of the public key in bits
+ * \param exponent public exponent (e.g., 65537)
+ *
+ * \note mbedtls_rsa_init() must be called beforehand to setup
+ * the RSA context.
+ *
+ * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code
+ */
+int mbedtls_rsa_gen_key( mbedtls_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ unsigned int nbits, int exponent );
+
+/**
+ * \brief Check a public RSA key
+ *
+ * \param ctx RSA context to be checked
+ *
+ * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code
+ */
+int mbedtls_rsa_check_pubkey( const mbedtls_rsa_context *ctx );
+
+/**
+ * \brief Check a private RSA key
+ *
+ * \param ctx RSA context to be checked
+ *
+ * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code
+ */
+int mbedtls_rsa_check_privkey( const mbedtls_rsa_context *ctx );
+
+/**
+ * \brief Check a public-private RSA key pair.
+ * Check each of the contexts, and make sure they match.
+ *
+ * \param pub RSA context holding the public key
+ * \param prv RSA context holding the private key
+ *
+ * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code
+ */
+int mbedtls_rsa_check_pub_priv( const mbedtls_rsa_context *pub, const mbedtls_rsa_context *prv );
+
+/**
+ * \brief Do an RSA public key operation
+ *
+ * \param ctx RSA context
+ * \param input input buffer
+ * \param output output buffer
+ *
+ * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code
+ *
+ * \note This function does NOT take care of message
+ * padding. Also, be sure to set input[0] = 0 or ensure that
+ * input is smaller than N.
+ *
+ * \note The input and output buffers must be large
+ * enough (eg. 128 bytes if RSA-1024 is used).
+ */
+int mbedtls_rsa_public( mbedtls_rsa_context *ctx,
+ const unsigned char *input,
+ unsigned char *output );
+
+/**
+ * \brief Do an RSA private key operation
+ *
+ * \param ctx RSA context
+ * \param f_rng RNG function (Needed for blinding)
+ * \param p_rng RNG parameter
+ * \param input input buffer
+ * \param output output buffer
+ *
+ * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code
+ *
+ * \note The input and output buffers must be large
+ * enough (eg. 128 bytes if RSA-1024 is used).
+ */
+int mbedtls_rsa_private( mbedtls_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ const unsigned char *input,
+ unsigned char *output );
+
+/**
+ * \brief Generic wrapper to perform a PKCS#1 encryption using the
+ * mode from the context. Add the message padding, then do an
+ * RSA operation.
+ *
+ * \param ctx RSA context
+ * \param f_rng RNG function (Needed for padding and PKCS#1 v2.1 encoding
+ * and MBEDTLS_RSA_PRIVATE)
+ * \param p_rng RNG parameter
+ * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE
+ * \param ilen contains the plaintext length
+ * \param input buffer holding the data to be encrypted
+ * \param output buffer that will hold the ciphertext
+ *
+ * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code
+ *
+ * \note The output buffer must be as large as the size
+ * of ctx->N (eg. 128 bytes if RSA-1024 is used).
+ */
+int mbedtls_rsa_pkcs1_encrypt( mbedtls_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ int mode, size_t ilen,
+ const unsigned char *input,
+ unsigned char *output );
+
+/**
+ * \brief Perform a PKCS#1 v1.5 encryption (RSAES-PKCS1-v1_5-ENCRYPT)
+ *
+ * \param ctx RSA context
+ * \param f_rng RNG function (Needed for padding and MBEDTLS_RSA_PRIVATE)
+ * \param p_rng RNG parameter
+ * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE
+ * \param ilen contains the plaintext length
+ * \param input buffer holding the data to be encrypted
+ * \param output buffer that will hold the ciphertext
+ *
+ * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code
+ *
+ * \note The output buffer must be as large as the size
+ * of ctx->N (eg. 128 bytes if RSA-1024 is used).
+ */
+int mbedtls_rsa_rsaes_pkcs1_v15_encrypt( mbedtls_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ int mode, size_t ilen,
+ const unsigned char *input,
+ unsigned char *output );
+
+/**
+ * \brief Perform a PKCS#1 v2.1 OAEP encryption (RSAES-OAEP-ENCRYPT)
+ *
+ * \param ctx RSA context
+ * \param f_rng RNG function (Needed for padding and PKCS#1 v2.1 encoding
+ * and MBEDTLS_RSA_PRIVATE)
+ * \param p_rng RNG parameter
+ * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE
+ * \param label buffer holding the custom label to use
+ * \param label_len contains the label length
+ * \param ilen contains the plaintext length
+ * \param input buffer holding the data to be encrypted
+ * \param output buffer that will hold the ciphertext
+ *
+ * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code
+ *
+ * \note The output buffer must be as large as the size
+ * of ctx->N (eg. 128 bytes if RSA-1024 is used).
+ */
+int mbedtls_rsa_rsaes_oaep_encrypt( mbedtls_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ int mode,
+ const unsigned char *label, size_t label_len,
+ size_t ilen,
+ const unsigned char *input,
+ unsigned char *output );
+
+/**
+ * \brief Generic wrapper to perform a PKCS#1 decryption using the
+ * mode from the context. Do an RSA operation, then remove
+ * the message padding
+ *
+ * \param ctx RSA context
+ * \param f_rng RNG function (Only needed for MBEDTLS_RSA_PRIVATE)
+ * \param p_rng RNG parameter
+ * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE
+ * \param olen will contain the plaintext length
+ * \param input buffer holding the encrypted data
+ * \param output buffer that will hold the plaintext
+ * \param output_max_len maximum length of the output buffer
+ *
+ * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code
+ *
+ * \note The output buffer length \c output_max_len should be
+ * as large as the size ctx->len of ctx->N (eg. 128 bytes
+ * if RSA-1024 is used) to be able to hold an arbitrary
+ * decrypted message. If it is not large enough to hold
+ * the decryption of the particular ciphertext provided,
+ * the function will return MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE.
+ *
+ * \note The input buffer must be as large as the size
+ * of ctx->N (eg. 128 bytes if RSA-1024 is used).
+ */
+int mbedtls_rsa_pkcs1_decrypt( mbedtls_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ int mode, size_t *olen,
+ const unsigned char *input,
+ unsigned char *output,
+ size_t output_max_len );
+
+/**
+ * \brief Perform a PKCS#1 v1.5 decryption (RSAES-PKCS1-v1_5-DECRYPT)
+ *
+ * \param ctx RSA context
+ * \param f_rng RNG function (Only needed for MBEDTLS_RSA_PRIVATE)
+ * \param p_rng RNG parameter
+ * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE
+ * \param olen will contain the plaintext length
+ * \param input buffer holding the encrypted data
+ * \param output buffer that will hold the plaintext
+ * \param output_max_len maximum length of the output buffer
+ *
+ * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code
+ *
+ * \note The output buffer length \c output_max_len should be
+ * as large as the size ctx->len of ctx->N (eg. 128 bytes
+ * if RSA-1024 is used) to be able to hold an arbitrary
+ * decrypted message. If it is not large enough to hold
+ * the decryption of the particular ciphertext provided,
+ * the function will return MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE.
+ *
+ * \note The input buffer must be as large as the size
+ * of ctx->N (eg. 128 bytes if RSA-1024 is used).
+ */
+int mbedtls_rsa_rsaes_pkcs1_v15_decrypt( mbedtls_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ int mode, size_t *olen,
+ const unsigned char *input,
+ unsigned char *output,
+ size_t output_max_len );
+
+/**
+ * \brief Perform a PKCS#1 v2.1 OAEP decryption (RSAES-OAEP-DECRYPT)
+ *
+ * \param ctx RSA context
+ * \param f_rng RNG function (Only needed for MBEDTLS_RSA_PRIVATE)
+ * \param p_rng RNG parameter
+ * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE
+ * \param label buffer holding the custom label to use
+ * \param label_len contains the label length
+ * \param olen will contain the plaintext length
+ * \param input buffer holding the encrypted data
+ * \param output buffer that will hold the plaintext
+ * \param output_max_len maximum length of the output buffer
+ *
+ * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code
+ *
+ * \note The output buffer length \c output_max_len should be
+ * as large as the size ctx->len of ctx->N (eg. 128 bytes
+ * if RSA-1024 is used) to be able to hold an arbitrary
+ * decrypted message. If it is not large enough to hold
+ * the decryption of the particular ciphertext provided,
+ * the function will return MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE.
+ *
+ * \note The input buffer must be as large as the size
+ * of ctx->N (eg. 128 bytes if RSA-1024 is used).
+ */
+int mbedtls_rsa_rsaes_oaep_decrypt( mbedtls_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ int mode,
+ const unsigned char *label, size_t label_len,
+ size_t *olen,
+ const unsigned char *input,
+ unsigned char *output,
+ size_t output_max_len );
+
+/**
+ * \brief Generic wrapper to perform a PKCS#1 signature using the
+ * mode from the context. Do a private RSA operation to sign
+ * a message digest
+ *
+ * \param ctx RSA context
+ * \param f_rng RNG function (Needed for PKCS#1 v2.1 encoding and for
+ * MBEDTLS_RSA_PRIVATE)
+ * \param p_rng RNG parameter
+ * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE
+ * \param md_alg a MBEDTLS_MD_XXX (use MBEDTLS_MD_NONE for signing raw data)
+ * \param hashlen message digest length (for MBEDTLS_MD_NONE only)
+ * \param hash buffer holding the message digest
+ * \param sig buffer that will hold the ciphertext
+ *
+ * \return 0 if the signing operation was successful,
+ * or an MBEDTLS_ERR_RSA_XXX error code
+ *
+ * \note The "sig" buffer must be as large as the size
+ * of ctx->N (eg. 128 bytes if RSA-1024 is used).
+ *
+ * \note In case of PKCS#1 v2.1 encoding, see comments on
+ * \note \c mbedtls_rsa_rsassa_pss_sign() for details on md_alg and hash_id.
+ */
+int mbedtls_rsa_pkcs1_sign( mbedtls_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ int mode,
+ mbedtls_md_type_t md_alg,
+ unsigned int hashlen,
+ const unsigned char *hash,
+ unsigned char *sig );
+
+/**
+ * \brief Perform a PKCS#1 v1.5 signature (RSASSA-PKCS1-v1_5-SIGN)
+ *
+ * \param ctx RSA context
+ * \param f_rng RNG function (Only needed for MBEDTLS_RSA_PRIVATE)
+ * \param p_rng RNG parameter
+ * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE
+ * \param md_alg a MBEDTLS_MD_XXX (use MBEDTLS_MD_NONE for signing raw data)
+ * \param hashlen message digest length (for MBEDTLS_MD_NONE only)
+ * \param hash buffer holding the message digest
+ * \param sig buffer that will hold the ciphertext
+ *
+ * \return 0 if the signing operation was successful,
+ * or an MBEDTLS_ERR_RSA_XXX error code
+ *
+ * \note The "sig" buffer must be as large as the size
+ * of ctx->N (eg. 128 bytes if RSA-1024 is used).
+ */
+int mbedtls_rsa_rsassa_pkcs1_v15_sign( mbedtls_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ int mode,
+ mbedtls_md_type_t md_alg,
+ unsigned int hashlen,
+ const unsigned char *hash,
+ unsigned char *sig );
+
+/**
+ * \brief Perform a PKCS#1 v2.1 PSS signature (RSASSA-PSS-SIGN)
+ *
+ * \param ctx RSA context
+ * \param f_rng RNG function (Needed for PKCS#1 v2.1 encoding and for
+ * MBEDTLS_RSA_PRIVATE)
+ * \param p_rng RNG parameter
+ * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE
+ * \param md_alg a MBEDTLS_MD_XXX (use MBEDTLS_MD_NONE for signing raw data)
+ * \param hashlen message digest length (for MBEDTLS_MD_NONE only)
+ * \param hash buffer holding the message digest
+ * \param sig buffer that will hold the ciphertext
+ *
+ * \return 0 if the signing operation was successful,
+ * or an MBEDTLS_ERR_RSA_XXX error code
+ *
+ * \note The "sig" buffer must be as large as the size
+ * of ctx->N (eg. 128 bytes if RSA-1024 is used).
+ *
+ * \note The hash_id in the RSA context is the one used for the
+ * encoding. md_alg in the function call is the type of hash
+ * that is encoded. According to RFC 3447 it is advised to
+ * keep both hashes the same.
+ */
+int mbedtls_rsa_rsassa_pss_sign( mbedtls_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ int mode,
+ mbedtls_md_type_t md_alg,
+ unsigned int hashlen,
+ const unsigned char *hash,
+ unsigned char *sig );
+
+/**
+ * \brief Generic wrapper to perform a PKCS#1 verification using the
+ * mode from the context. Do a public RSA operation and check
+ * the message digest
+ *
+ * \param ctx points to an RSA public key
+ * \param f_rng RNG function (Only needed for MBEDTLS_RSA_PRIVATE)
+ * \param p_rng RNG parameter
+ * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE
+ * \param md_alg a MBEDTLS_MD_XXX (use MBEDTLS_MD_NONE for signing raw data)
+ * \param hashlen message digest length (for MBEDTLS_MD_NONE only)
+ * \param hash buffer holding the message digest
+ * \param sig buffer holding the ciphertext
+ *
+ * \return 0 if the verify operation was successful,
+ * or an MBEDTLS_ERR_RSA_XXX error code
+ *
+ * \note The "sig" buffer must be as large as the size
+ * of ctx->N (eg. 128 bytes if RSA-1024 is used).
+ *
+ * \note In case of PKCS#1 v2.1 encoding, see comments on
+ * \c mbedtls_rsa_rsassa_pss_verify() about md_alg and hash_id.
+ */
+int mbedtls_rsa_pkcs1_verify( mbedtls_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ int mode,
+ mbedtls_md_type_t md_alg,
+ unsigned int hashlen,
+ const unsigned char *hash,
+ const unsigned char *sig );
+
+/**
+ * \brief Perform a PKCS#1 v1.5 verification (RSASSA-PKCS1-v1_5-VERIFY)
+ *
+ * \param ctx points to an RSA public key
+ * \param f_rng RNG function (Only needed for MBEDTLS_RSA_PRIVATE)
+ * \param p_rng RNG parameter
+ * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE
+ * \param md_alg a MBEDTLS_MD_XXX (use MBEDTLS_MD_NONE for signing raw data)
+ * \param hashlen message digest length (for MBEDTLS_MD_NONE only)
+ * \param hash buffer holding the message digest
+ * \param sig buffer holding the ciphertext
+ *
+ * \return 0 if the verify operation was successful,
+ * or an MBEDTLS_ERR_RSA_XXX error code
+ *
+ * \note The "sig" buffer must be as large as the size
+ * of ctx->N (eg. 128 bytes if RSA-1024 is used).
+ */
+int mbedtls_rsa_rsassa_pkcs1_v15_verify( mbedtls_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ int mode,
+ mbedtls_md_type_t md_alg,
+ unsigned int hashlen,
+ const unsigned char *hash,
+ const unsigned char *sig );
+
+/**
+ * \brief Perform a PKCS#1 v2.1 PSS verification (RSASSA-PSS-VERIFY)
+ * (This is the "simple" version.)
+ *
+ * \param ctx points to an RSA public key
+ * \param f_rng RNG function (Only needed for MBEDTLS_RSA_PRIVATE)
+ * \param p_rng RNG parameter
+ * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE
+ * \param md_alg a MBEDTLS_MD_XXX (use MBEDTLS_MD_NONE for signing raw data)
+ * \param hashlen message digest length (for MBEDTLS_MD_NONE only)
+ * \param hash buffer holding the message digest
+ * \param sig buffer holding the ciphertext
+ *
+ * \return 0 if the verify operation was successful,
+ * or an MBEDTLS_ERR_RSA_XXX error code
+ *
+ * \note The "sig" buffer must be as large as the size
+ * of ctx->N (eg. 128 bytes if RSA-1024 is used).
+ *
+ * \note The hash_id in the RSA context is the one used for the
+ * verification. md_alg in the function call is the type of
+ * hash that is verified. According to RFC 3447 it is advised to
+ * keep both hashes the same. If hash_id in the RSA context is
+ * unset, the md_alg from the function call is used.
+ */
+int mbedtls_rsa_rsassa_pss_verify( mbedtls_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ int mode,
+ mbedtls_md_type_t md_alg,
+ unsigned int hashlen,
+ const unsigned char *hash,
+ const unsigned char *sig );
+
+/**
+ * \brief Perform a PKCS#1 v2.1 PSS verification (RSASSA-PSS-VERIFY)
+ * (This is the version with "full" options.)
+ *
+ * \param ctx points to an RSA public key
+ * \param f_rng RNG function (Only needed for MBEDTLS_RSA_PRIVATE)
+ * \param p_rng RNG parameter
+ * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE
+ * \param md_alg a MBEDTLS_MD_XXX (use MBEDTLS_MD_NONE for signing raw data)
+ * \param hashlen message digest length (for MBEDTLS_MD_NONE only)
+ * \param hash buffer holding the message digest
+ * \param mgf1_hash_id message digest used for mask generation
+ * \param expected_salt_len Length of the salt used in padding, use
+ * MBEDTLS_RSA_SALT_LEN_ANY to accept any salt length
+ * \param sig buffer holding the ciphertext
+ *
+ * \return 0 if the verify operation was successful,
+ * or an MBEDTLS_ERR_RSA_XXX error code
+ *
+ * \note The "sig" buffer must be as large as the size
+ * of ctx->N (eg. 128 bytes if RSA-1024 is used).
+ *
+ * \note The hash_id in the RSA context is ignored.
+ */
+int mbedtls_rsa_rsassa_pss_verify_ext( mbedtls_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ int mode,
+ mbedtls_md_type_t md_alg,
+ unsigned int hashlen,
+ const unsigned char *hash,
+ mbedtls_md_type_t mgf1_hash_id,
+ int expected_salt_len,
+ const unsigned char *sig );
+
+/**
+ * \brief Copy the components of an RSA context
+ *
+ * \param dst Destination context
+ * \param src Source context
+ *
+ * \return 0 on success,
+ * MBEDTLS_ERR_MPI_ALLOC_FAILED on memory allocation failure
+ */
+int mbedtls_rsa_copy( mbedtls_rsa_context *dst, const mbedtls_rsa_context *src );
+
+/**
+ * \brief Free the components of an RSA key
+ *
+ * \param ctx RSA Context to free
+ */
+void mbedtls_rsa_free( mbedtls_rsa_context *ctx );
+
+/**
+ * \brief Checkup routine
+ *
+ * \return 0 if successful, or 1 if the test failed
+ */
+int mbedtls_rsa_self_test( int verbose );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MBEDTLS_RSA_C */
+
+#endif /* rsa.h */
diff --git a/backport/compat/verification/mbedtls/sha1.h b/backport/compat/verification/mbedtls/sha1.h
new file mode 100644
index 00000000..b8752edd
--- /dev/null
+++ b/backport/compat/verification/mbedtls/sha1.h
@@ -0,0 +1,135 @@
+/**
+ * \file sha1.h
+ *
+ * \brief SHA-1 cryptographic hash function
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: GPL-2.0
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * This file is part of mbed TLS (https://tls.mbed.org)
+ */
+#ifndef MBEDTLS_SHA1_H
+#define MBEDTLS_SHA1_H
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#if !defined(MBEDTLS_SHA1_ALT)
+// Regular implementation
+//
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief SHA-1 context structure
+ */
+typedef struct
+{
+ uint32_t total[2]; /*!< number of bytes processed */
+ uint32_t state[5]; /*!< intermediate digest state */
+ unsigned char buffer[64]; /*!< data block being processed */
+}
+mbedtls_sha1_context;
+
+/**
+ * \brief Initialize SHA-1 context
+ *
+ * \param ctx SHA-1 context to be initialized
+ */
+void mbedtls_sha1_init( mbedtls_sha1_context *ctx );
+
+/**
+ * \brief Clear SHA-1 context
+ *
+ * \param ctx SHA-1 context to be cleared
+ */
+void mbedtls_sha1_free( mbedtls_sha1_context *ctx );
+
+/**
+ * \brief Clone (the state of) a SHA-1 context
+ *
+ * \param dst The destination context
+ * \param src The context to be cloned
+ */
+void mbedtls_sha1_clone( mbedtls_sha1_context *dst,
+ const mbedtls_sha1_context *src );
+
+/**
+ * \brief SHA-1 context setup
+ *
+ * \param ctx context to be initialized
+ */
+void mbedtls_sha1_starts( mbedtls_sha1_context *ctx );
+
+/**
+ * \brief SHA-1 process buffer
+ *
+ * \param ctx SHA-1 context
+ * \param input buffer holding the data
+ * \param ilen length of the input data
+ */
+void mbedtls_sha1_update( mbedtls_sha1_context *ctx, const unsigned char *input, size_t ilen );
+
+/**
+ * \brief SHA-1 final digest
+ *
+ * \param ctx SHA-1 context
+ * \param output SHA-1 checksum result
+ */
+void mbedtls_sha1_finish( mbedtls_sha1_context *ctx, unsigned char output[20] );
+
+/* Internal use */
+void mbedtls_sha1_process( mbedtls_sha1_context *ctx, const unsigned char data[64] );
+
+#ifdef __cplusplus
+}
+#endif
+
+#else /* MBEDTLS_SHA1_ALT */
+#include "sha1_alt.h"
+#endif /* MBEDTLS_SHA1_ALT */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Output = SHA-1( input buffer )
+ *
+ * \param input buffer holding the data
+ * \param ilen length of the input data
+ * \param output SHA-1 checksum result
+ */
+void mbedtls_sha1( const unsigned char *input, size_t ilen, unsigned char output[20] );
+
+/**
+ * \brief Checkup routine
+ *
+ * \return 0 if successful, or 1 if the test failed
+ */
+int mbedtls_sha1_self_test( int verbose );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* mbedtls_sha1.h */
diff --git a/backport/compat/verification/mbedtls/sha256.h b/backport/compat/verification/mbedtls/sha256.h
new file mode 100644
index 00000000..68223f0b
--- /dev/null
+++ b/backport/compat/verification/mbedtls/sha256.h
@@ -0,0 +1,140 @@
+/**
+ * \file sha256.h
+ *
+ * \brief SHA-224 and SHA-256 cryptographic hash function
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: GPL-2.0
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * This file is part of mbed TLS (https://tls.mbed.org)
+ */
+#ifndef MBEDTLS_SHA256_H
+#define MBEDTLS_SHA256_H
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#if !defined(MBEDTLS_SHA256_ALT)
+// Regular implementation
+//
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief SHA-256 context structure
+ */
+typedef struct
+{
+ uint32_t total[2]; /*!< number of bytes processed */
+ uint32_t state[8]; /*!< intermediate digest state */
+ unsigned char buffer[64]; /*!< data block being processed */
+ int is224; /*!< 0 => SHA-256, else SHA-224 */
+}
+mbedtls_sha256_context;
+
+/**
+ * \brief Initialize SHA-256 context
+ *
+ * \param ctx SHA-256 context to be initialized
+ */
+void mbedtls_sha256_init( mbedtls_sha256_context *ctx );
+
+/**
+ * \brief Clear SHA-256 context
+ *
+ * \param ctx SHA-256 context to be cleared
+ */
+void mbedtls_sha256_free( mbedtls_sha256_context *ctx );
+
+/**
+ * \brief Clone (the state of) a SHA-256 context
+ *
+ * \param dst The destination context
+ * \param src The context to be cloned
+ */
+void mbedtls_sha256_clone( mbedtls_sha256_context *dst,
+ const mbedtls_sha256_context *src );
+
+/**
+ * \brief SHA-256 context setup
+ *
+ * \param ctx context to be initialized
+ * \param is224 0 = use SHA256, 1 = use SHA224
+ */
+void mbedtls_sha256_starts( mbedtls_sha256_context *ctx, int is224 );
+
+/**
+ * \brief SHA-256 process buffer
+ *
+ * \param ctx SHA-256 context
+ * \param input buffer holding the data
+ * \param ilen length of the input data
+ */
+void mbedtls_sha256_update( mbedtls_sha256_context *ctx, const unsigned char *input,
+ size_t ilen );
+
+/**
+ * \brief SHA-256 final digest
+ *
+ * \param ctx SHA-256 context
+ * \param output SHA-224/256 checksum result
+ */
+void mbedtls_sha256_finish( mbedtls_sha256_context *ctx, unsigned char output[32] );
+
+/* Internal use */
+void mbedtls_sha256_process( mbedtls_sha256_context *ctx, const unsigned char data[64] );
+
+#ifdef __cplusplus
+}
+#endif
+
+#else /* MBEDTLS_SHA256_ALT */
+#include "sha256_alt.h"
+#endif /* MBEDTLS_SHA256_ALT */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Output = SHA-256( input buffer )
+ *
+ * \param input buffer holding the data
+ * \param ilen length of the input data
+ * \param output SHA-224/256 checksum result
+ * \param is224 0 = use SHA256, 1 = use SHA224
+ */
+void mbedtls_sha256( const unsigned char *input, size_t ilen,
+ unsigned char output[32], int is224 );
+
+/**
+ * \brief Checkup routine
+ *
+ * \return 0 if successful, or 1 if the test failed
+ */
+int mbedtls_sha256_self_test( int verbose );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* mbedtls_sha256.h */
diff --git a/backport/compat/verification/md.c b/backport/compat/verification/md.c
new file mode 100644
index 00000000..cff07534
--- /dev/null
+++ b/backport/compat/verification/md.c
@@ -0,0 +1,471 @@
+/**
+ * \file mbedtls_md.c
+ *
+ * \brief Generic message digest wrapper for mbed TLS
+ *
+ * \author Adriaan de Jong <dejong@fox-it.com>
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: GPL-2.0
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * This file is part of mbed TLS (https://tls.mbed.org)
+ */
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "mbedtls/config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#if defined(MBEDTLS_MD_C)
+
+#include "mbedtls/md.h"
+#include "mbedtls/md_internal.h"
+
+#if defined(MBEDTLS_PLATFORM_C)
+#include "mbedtls/platform.h"
+#else
+#include <stdlib.h>
+#define mbedtls_calloc calloc
+#define mbedtls_free free
+#endif
+
+#if defined(MBEDTLS_FS_IO)
+#include <stdio.h>
+#endif
+
+/* Implementation that should never be optimized out by the compiler */
+static void mbedtls_zeroize( void *v, size_t n ) {
+ volatile unsigned char *p = v; while( n-- ) *p++ = 0;
+}
+
+/*
+ * Reminder: update profiles in x509_crt.c when adding a new hash!
+ */
+static const int supported_digests[] = {
+
+#if defined(MBEDTLS_SHA512_C)
+ MBEDTLS_MD_SHA512,
+ MBEDTLS_MD_SHA384,
+#endif
+
+#if defined(MBEDTLS_SHA256_C)
+ MBEDTLS_MD_SHA256,
+ MBEDTLS_MD_SHA224,
+#endif
+
+#if defined(MBEDTLS_SHA1_C)
+ MBEDTLS_MD_SHA1,
+#endif
+
+#if defined(MBEDTLS_RIPEMD160_C)
+ MBEDTLS_MD_RIPEMD160,
+#endif
+
+#if defined(MBEDTLS_MD5_C)
+ MBEDTLS_MD_MD5,
+#endif
+
+#if defined(MBEDTLS_MD4_C)
+ MBEDTLS_MD_MD4,
+#endif
+
+#if defined(MBEDTLS_MD2_C)
+ MBEDTLS_MD_MD2,
+#endif
+
+ MBEDTLS_MD_NONE
+};
+
+const int *mbedtls_md_list( void )
+{
+ return( supported_digests );
+}
+
+const mbedtls_md_info_t *mbedtls_md_info_from_string( const char *md_name )
+{
+ if( NULL == md_name )
+ return( NULL );
+
+ /* Get the appropriate digest information */
+#if defined(MBEDTLS_MD2_C)
+ if( !strcmp( "MD2", md_name ) )
+ return mbedtls_md_info_from_type( MBEDTLS_MD_MD2 );
+#endif
+#if defined(MBEDTLS_MD4_C)
+ if( !strcmp( "MD4", md_name ) )
+ return mbedtls_md_info_from_type( MBEDTLS_MD_MD4 );
+#endif
+#if defined(MBEDTLS_MD5_C)
+ if( !strcmp( "MD5", md_name ) )
+ return mbedtls_md_info_from_type( MBEDTLS_MD_MD5 );
+#endif
+#if defined(MBEDTLS_RIPEMD160_C)
+ if( !strcmp( "RIPEMD160", md_name ) )
+ return mbedtls_md_info_from_type( MBEDTLS_MD_RIPEMD160 );
+#endif
+#if defined(MBEDTLS_SHA1_C)
+ if( !strcmp( "SHA1", md_name ) || !strcmp( "SHA", md_name ) )
+ return mbedtls_md_info_from_type( MBEDTLS_MD_SHA1 );
+#endif
+#if defined(MBEDTLS_SHA256_C)
+ if( !strcmp( "SHA224", md_name ) )
+ return mbedtls_md_info_from_type( MBEDTLS_MD_SHA224 );
+ if( !strcmp( "SHA256", md_name ) )
+ return mbedtls_md_info_from_type( MBEDTLS_MD_SHA256 );
+#endif
+#if defined(MBEDTLS_SHA512_C)
+ if( !strcmp( "SHA384", md_name ) )
+ return mbedtls_md_info_from_type( MBEDTLS_MD_SHA384 );
+ if( !strcmp( "SHA512", md_name ) )
+ return mbedtls_md_info_from_type( MBEDTLS_MD_SHA512 );
+#endif
+ return( NULL );
+}
+
+const mbedtls_md_info_t *mbedtls_md_info_from_type( mbedtls_md_type_t md_type )
+{
+ switch( md_type )
+ {
+#if defined(MBEDTLS_MD2_C)
+ case MBEDTLS_MD_MD2:
+ return( &mbedtls_md2_info );
+#endif
+#if defined(MBEDTLS_MD4_C)
+ case MBEDTLS_MD_MD4:
+ return( &mbedtls_md4_info );
+#endif
+#if defined(MBEDTLS_MD5_C)
+ case MBEDTLS_MD_MD5:
+ return( &mbedtls_md5_info );
+#endif
+#if defined(MBEDTLS_RIPEMD160_C)
+ case MBEDTLS_MD_RIPEMD160:
+ return( &mbedtls_ripemd160_info );
+#endif
+#if defined(MBEDTLS_SHA1_C)
+ case MBEDTLS_MD_SHA1:
+ return( &mbedtls_sha1_info );
+#endif
+#if defined(MBEDTLS_SHA256_C)
+ case MBEDTLS_MD_SHA224:
+ return( &mbedtls_sha224_info );
+ case MBEDTLS_MD_SHA256:
+ return( &mbedtls_sha256_info );
+#endif
+#if defined(MBEDTLS_SHA512_C)
+ case MBEDTLS_MD_SHA384:
+ return( &mbedtls_sha384_info );
+ case MBEDTLS_MD_SHA512:
+ return( &mbedtls_sha512_info );
+#endif
+ default:
+ return( NULL );
+ }
+}
+
+void mbedtls_md_init( mbedtls_md_context_t *ctx )
+{
+ memset( ctx, 0, sizeof( mbedtls_md_context_t ) );
+}
+
+void mbedtls_md_free( mbedtls_md_context_t *ctx )
+{
+ if( ctx == NULL || ctx->md_info == NULL )
+ return;
+
+ if( ctx->md_ctx != NULL )
+ ctx->md_info->ctx_free_func( ctx->md_ctx );
+
+ if( ctx->hmac_ctx != NULL )
+ {
+ mbedtls_zeroize( ctx->hmac_ctx, 2 * ctx->md_info->block_size );
+ mbedtls_free( ctx->hmac_ctx );
+ }
+
+ mbedtls_zeroize( ctx, sizeof( mbedtls_md_context_t ) );
+}
+
+int mbedtls_md_clone( mbedtls_md_context_t *dst,
+ const mbedtls_md_context_t *src )
+{
+ if( dst == NULL || dst->md_info == NULL ||
+ src == NULL || src->md_info == NULL ||
+ dst->md_info != src->md_info )
+ {
+ return( MBEDTLS_ERR_MD_BAD_INPUT_DATA );
+ }
+
+ dst->md_info->clone_func( dst->md_ctx, src->md_ctx );
+
+ return( 0 );
+}
+
+#if ! defined(MBEDTLS_DEPRECATED_REMOVED)
+int mbedtls_md_init_ctx( mbedtls_md_context_t *ctx, const mbedtls_md_info_t *md_info )
+{
+ return mbedtls_md_setup( ctx, md_info, 1 );
+}
+#endif
+
+int mbedtls_md_setup( mbedtls_md_context_t *ctx, const mbedtls_md_info_t *md_info, int hmac )
+{
+ if( md_info == NULL || ctx == NULL )
+ return( MBEDTLS_ERR_MD_BAD_INPUT_DATA );
+
+ if( ( ctx->md_ctx = md_info->ctx_alloc_func() ) == NULL )
+ return( MBEDTLS_ERR_MD_ALLOC_FAILED );
+
+ if( hmac != 0 )
+ {
+ ctx->hmac_ctx = mbedtls_calloc( 2, md_info->block_size );
+ if( ctx->hmac_ctx == NULL )
+ {
+ md_info->ctx_free_func( ctx->md_ctx );
+ return( MBEDTLS_ERR_MD_ALLOC_FAILED );
+ }
+ }
+
+ ctx->md_info = md_info;
+
+ return( 0 );
+}
+
+int mbedtls_md_starts( mbedtls_md_context_t *ctx )
+{
+ if( ctx == NULL || ctx->md_info == NULL )
+ return( MBEDTLS_ERR_MD_BAD_INPUT_DATA );
+
+ ctx->md_info->starts_func( ctx->md_ctx );
+
+ return( 0 );
+}
+
+int mbedtls_md_update( mbedtls_md_context_t *ctx, const unsigned char *input, size_t ilen )
+{
+ if( ctx == NULL || ctx->md_info == NULL )
+ return( MBEDTLS_ERR_MD_BAD_INPUT_DATA );
+
+ ctx->md_info->update_func( ctx->md_ctx, input, ilen );
+
+ return( 0 );
+}
+
+int mbedtls_md_finish( mbedtls_md_context_t *ctx, unsigned char *output )
+{
+ if( ctx == NULL || ctx->md_info == NULL )
+ return( MBEDTLS_ERR_MD_BAD_INPUT_DATA );
+
+ ctx->md_info->finish_func( ctx->md_ctx, output );
+
+ return( 0 );
+}
+
+int mbedtls_md( const mbedtls_md_info_t *md_info, const unsigned char *input, size_t ilen,
+ unsigned char *output )
+{
+ if( md_info == NULL )
+ return( MBEDTLS_ERR_MD_BAD_INPUT_DATA );
+
+ md_info->digest_func( input, ilen, output );
+
+ return( 0 );
+}
+
+#if defined(MBEDTLS_FS_IO)
+int mbedtls_md_file( const mbedtls_md_info_t *md_info, const char *path, unsigned char *output )
+{
+ int ret;
+ FILE *f;
+ size_t n;
+ mbedtls_md_context_t ctx;
+ unsigned char buf[1024];
+
+ if( md_info == NULL )
+ return( MBEDTLS_ERR_MD_BAD_INPUT_DATA );
+
+ if( ( f = fopen( path, "rb" ) ) == NULL )
+ return( MBEDTLS_ERR_MD_FILE_IO_ERROR );
+
+ mbedtls_md_init( &ctx );
+
+ if( ( ret = mbedtls_md_setup( &ctx, md_info, 0 ) ) != 0 )
+ goto cleanup;
+
+ md_info->starts_func( ctx.md_ctx );
+
+ while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 )
+ md_info->update_func( ctx.md_ctx, buf, n );
+
+ if( ferror( f ) != 0 )
+ {
+ ret = MBEDTLS_ERR_MD_FILE_IO_ERROR;
+ goto cleanup;
+ }
+
+ md_info->finish_func( ctx.md_ctx, output );
+
+cleanup:
+ fclose( f );
+ mbedtls_md_free( &ctx );
+
+ return( ret );
+}
+#endif /* MBEDTLS_FS_IO */
+
+int mbedtls_md_hmac_starts( mbedtls_md_context_t *ctx, const unsigned char *key, size_t keylen )
+{
+ unsigned char sum[MBEDTLS_MD_MAX_SIZE];
+ unsigned char *ipad, *opad;
+ size_t i;
+
+ if( ctx == NULL || ctx->md_info == NULL || ctx->hmac_ctx == NULL )
+ return( MBEDTLS_ERR_MD_BAD_INPUT_DATA );
+
+ if( keylen > (size_t) ctx->md_info->block_size )
+ {
+ ctx->md_info->starts_func( ctx->md_ctx );
+ ctx->md_info->update_func( ctx->md_ctx, key, keylen );
+ ctx->md_info->finish_func( ctx->md_ctx, sum );
+
+ keylen = ctx->md_info->size;
+ key = sum;
+ }
+
+ ipad = (unsigned char *) ctx->hmac_ctx;
+ opad = (unsigned char *) ctx->hmac_ctx + ctx->md_info->block_size;
+
+ memset( ipad, 0x36, ctx->md_info->block_size );
+ memset( opad, 0x5C, ctx->md_info->block_size );
+
+ for( i = 0; i < keylen; i++ )
+ {
+ ipad[i] = (unsigned char)( ipad[i] ^ key[i] );
+ opad[i] = (unsigned char)( opad[i] ^ key[i] );
+ }
+
+ mbedtls_zeroize( sum, sizeof( sum ) );
+
+ ctx->md_info->starts_func( ctx->md_ctx );
+ ctx->md_info->update_func( ctx->md_ctx, ipad, ctx->md_info->block_size );
+
+ return( 0 );
+}
+
+int mbedtls_md_hmac_update( mbedtls_md_context_t *ctx, const unsigned char *input, size_t ilen )
+{
+ if( ctx == NULL || ctx->md_info == NULL || ctx->hmac_ctx == NULL )
+ return( MBEDTLS_ERR_MD_BAD_INPUT_DATA );
+
+ ctx->md_info->update_func( ctx->md_ctx, input, ilen );
+
+ return( 0 );
+}
+
+int mbedtls_md_hmac_finish( mbedtls_md_context_t *ctx, unsigned char *output )
+{
+ unsigned char tmp[MBEDTLS_MD_MAX_SIZE];
+ unsigned char *opad;
+
+ if( ctx == NULL || ctx->md_info == NULL || ctx->hmac_ctx == NULL )
+ return( MBEDTLS_ERR_MD_BAD_INPUT_DATA );
+
+ opad = (unsigned char *) ctx->hmac_ctx + ctx->md_info->block_size;
+
+ ctx->md_info->finish_func( ctx->md_ctx, tmp );
+ ctx->md_info->starts_func( ctx->md_ctx );
+ ctx->md_info->update_func( ctx->md_ctx, opad, ctx->md_info->block_size );
+ ctx->md_info->update_func( ctx->md_ctx, tmp, ctx->md_info->size );
+ ctx->md_info->finish_func( ctx->md_ctx, output );
+
+ return( 0 );
+}
+
+int mbedtls_md_hmac_reset( mbedtls_md_context_t *ctx )
+{
+ unsigned char *ipad;
+
+ if( ctx == NULL || ctx->md_info == NULL || ctx->hmac_ctx == NULL )
+ return( MBEDTLS_ERR_MD_BAD_INPUT_DATA );
+
+ ipad = (unsigned char *) ctx->hmac_ctx;
+
+ ctx->md_info->starts_func( ctx->md_ctx );
+ ctx->md_info->update_func( ctx->md_ctx, ipad, ctx->md_info->block_size );
+
+ return( 0 );
+}
+
+int mbedtls_md_hmac( const mbedtls_md_info_t *md_info, const unsigned char *key, size_t keylen,
+ const unsigned char *input, size_t ilen,
+ unsigned char *output )
+{
+ mbedtls_md_context_t ctx;
+ int ret;
+
+ if( md_info == NULL )
+ return( MBEDTLS_ERR_MD_BAD_INPUT_DATA );
+
+ mbedtls_md_init( &ctx );
+
+ if( ( ret = mbedtls_md_setup( &ctx, md_info, 1 ) ) != 0 )
+ return( ret );
+
+ mbedtls_md_hmac_starts( &ctx, key, keylen );
+ mbedtls_md_hmac_update( &ctx, input, ilen );
+ mbedtls_md_hmac_finish( &ctx, output );
+
+ mbedtls_md_free( &ctx );
+
+ return( 0 );
+}
+
+int mbedtls_md_process( mbedtls_md_context_t *ctx, const unsigned char *data )
+{
+ if( ctx == NULL || ctx->md_info == NULL )
+ return( MBEDTLS_ERR_MD_BAD_INPUT_DATA );
+
+ ctx->md_info->process_func( ctx->md_ctx, data );
+
+ return( 0 );
+}
+
+unsigned char mbedtls_md_get_size( const mbedtls_md_info_t *md_info )
+{
+ if( md_info == NULL )
+ return( 0 );
+
+ return md_info->size;
+}
+
+mbedtls_md_type_t mbedtls_md_get_type( const mbedtls_md_info_t *md_info )
+{
+ if( md_info == NULL )
+ return( MBEDTLS_MD_NONE );
+
+ return md_info->type;
+}
+
+const char *mbedtls_md_get_name( const mbedtls_md_info_t *md_info )
+{
+ if( md_info == NULL )
+ return( NULL );
+
+ return md_info->name;
+}
+
+#endif /* MBEDTLS_MD_C */
diff --git a/backport/compat/verification/md_wrap.c b/backport/compat/verification/md_wrap.c
new file mode 100644
index 00000000..49c47d69
--- /dev/null
+++ b/backport/compat/verification/md_wrap.c
@@ -0,0 +1,577 @@
+/**
+ * \file md_wrap.c
+ *
+ * \brief Generic message digest wrapper for mbed TLS
+ *
+ * \author Adriaan de Jong <dejong@fox-it.com>
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: GPL-2.0
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * This file is part of mbed TLS (https://tls.mbed.org)
+ */
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "mbedtls/config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#if defined(MBEDTLS_MD_C)
+
+#include "mbedtls/md_internal.h"
+
+#if defined(MBEDTLS_MD2_C)
+#include "mbedtls/md2.h"
+#endif
+
+#if defined(MBEDTLS_MD4_C)
+#include "mbedtls/md4.h"
+#endif
+
+#if defined(MBEDTLS_MD5_C)
+#include "mbedtls/md5.h"
+#endif
+
+#if defined(MBEDTLS_RIPEMD160_C)
+#include "mbedtls/ripemd160.h"
+#endif
+
+#if defined(MBEDTLS_SHA1_C)
+#include "mbedtls/sha1.h"
+#endif
+
+#if defined(MBEDTLS_SHA256_C)
+#include "mbedtls/sha256.h"
+#endif
+
+#if defined(MBEDTLS_SHA512_C)
+#include "mbedtls/sha512.h"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_C)
+#include "mbedtls/platform.h"
+#else
+#include <stdlib.h>
+#define mbedtls_calloc calloc
+#define mbedtls_free free
+#endif
+
+#if defined(MBEDTLS_MD2_C)
+
+static void md2_starts_wrap( void *ctx )
+{
+ mbedtls_md2_starts( (mbedtls_md2_context *) ctx );
+}
+
+static void md2_update_wrap( void *ctx, const unsigned char *input,
+ size_t ilen )
+{
+ mbedtls_md2_update( (mbedtls_md2_context *) ctx, input, ilen );
+}
+
+static void md2_finish_wrap( void *ctx, unsigned char *output )
+{
+ mbedtls_md2_finish( (mbedtls_md2_context *) ctx, output );
+}
+
+static void *md2_ctx_alloc( void )
+{
+ void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_md2_context ) );
+
+ if( ctx != NULL )
+ mbedtls_md2_init( (mbedtls_md2_context *) ctx );
+
+ return( ctx );
+}
+
+static void md2_ctx_free( void *ctx )
+{
+ mbedtls_md2_free( (mbedtls_md2_context *) ctx );
+ mbedtls_free( ctx );
+}
+
+static void md2_clone_wrap( void *dst, const void *src )
+{
+ mbedtls_md2_clone( (mbedtls_md2_context *) dst,
+ (const mbedtls_md2_context *) src );
+}
+
+static void md2_process_wrap( void *ctx, const unsigned char *data )
+{
+ ((void) data);
+
+ mbedtls_md2_process( (mbedtls_md2_context *) ctx );
+}
+
+const mbedtls_md_info_t mbedtls_md2_info = {
+ MBEDTLS_MD_MD2,
+ "MD2",
+ 16,
+ 16,
+ md2_starts_wrap,
+ md2_update_wrap,
+ md2_finish_wrap,
+ mbedtls_md2,
+ md2_ctx_alloc,
+ md2_ctx_free,
+ md2_clone_wrap,
+ md2_process_wrap,
+};
+
+#endif /* MBEDTLS_MD2_C */
+
+#if defined(MBEDTLS_MD4_C)
+
+static void md4_starts_wrap( void *ctx )
+{
+ mbedtls_md4_starts( (mbedtls_md4_context *) ctx );
+}
+
+static void md4_update_wrap( void *ctx, const unsigned char *input,
+ size_t ilen )
+{
+ mbedtls_md4_update( (mbedtls_md4_context *) ctx, input, ilen );
+}
+
+static void md4_finish_wrap( void *ctx, unsigned char *output )
+{
+ mbedtls_md4_finish( (mbedtls_md4_context *) ctx, output );
+}
+
+static void *md4_ctx_alloc( void )
+{
+ void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_md4_context ) );
+
+ if( ctx != NULL )
+ mbedtls_md4_init( (mbedtls_md4_context *) ctx );
+
+ return( ctx );
+}
+
+static void md4_ctx_free( void *ctx )
+{
+ mbedtls_md4_free( (mbedtls_md4_context *) ctx );
+ mbedtls_free( ctx );
+}
+
+static void md4_clone_wrap( void *dst, const void *src )
+{
+ mbedtls_md4_clone( (mbedtls_md4_context *) dst,
+ (const mbedtls_md4_context *) src );
+}
+
+static void md4_process_wrap( void *ctx, const unsigned char *data )
+{
+ mbedtls_md4_process( (mbedtls_md4_context *) ctx, data );
+}
+
+const mbedtls_md_info_t mbedtls_md4_info = {
+ MBEDTLS_MD_MD4,
+ "MD4",
+ 16,
+ 64,
+ md4_starts_wrap,
+ md4_update_wrap,
+ md4_finish_wrap,
+ mbedtls_md4,
+ md4_ctx_alloc,
+ md4_ctx_free,
+ md4_clone_wrap,
+ md4_process_wrap,
+};
+
+#endif /* MBEDTLS_MD4_C */
+
+#if defined(MBEDTLS_MD5_C)
+
+static void md5_starts_wrap( void *ctx )
+{
+ mbedtls_md5_starts( (mbedtls_md5_context *) ctx );
+}
+
+static void md5_update_wrap( void *ctx, const unsigned char *input,
+ size_t ilen )
+{
+ mbedtls_md5_update( (mbedtls_md5_context *) ctx, input, ilen );
+}
+
+static void md5_finish_wrap( void *ctx, unsigned char *output )
+{
+ mbedtls_md5_finish( (mbedtls_md5_context *) ctx, output );
+}
+
+static void *md5_ctx_alloc( void )
+{
+ void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_md5_context ) );
+
+ if( ctx != NULL )
+ mbedtls_md5_init( (mbedtls_md5_context *) ctx );
+
+ return( ctx );
+}
+
+static void md5_ctx_free( void *ctx )
+{
+ mbedtls_md5_free( (mbedtls_md5_context *) ctx );
+ mbedtls_free( ctx );
+}
+
+static void md5_clone_wrap( void *dst, const void *src )
+{
+ mbedtls_md5_clone( (mbedtls_md5_context *) dst,
+ (const mbedtls_md5_context *) src );
+}
+
+static void md5_process_wrap( void *ctx, const unsigned char *data )
+{
+ mbedtls_md5_process( (mbedtls_md5_context *) ctx, data );
+}
+
+const mbedtls_md_info_t mbedtls_md5_info = {
+ MBEDTLS_MD_MD5,
+ "MD5",
+ 16,
+ 64,
+ md5_starts_wrap,
+ md5_update_wrap,
+ md5_finish_wrap,
+ mbedtls_md5,
+ md5_ctx_alloc,
+ md5_ctx_free,
+ md5_clone_wrap,
+ md5_process_wrap,
+};
+
+#endif /* MBEDTLS_MD5_C */
+
+#if defined(MBEDTLS_RIPEMD160_C)
+
+static void ripemd160_starts_wrap( void *ctx )
+{
+ mbedtls_ripemd160_starts( (mbedtls_ripemd160_context *) ctx );
+}
+
+static void ripemd160_update_wrap( void *ctx, const unsigned char *input,
+ size_t ilen )
+{
+ mbedtls_ripemd160_update( (mbedtls_ripemd160_context *) ctx, input, ilen );
+}
+
+static void ripemd160_finish_wrap( void *ctx, unsigned char *output )
+{
+ mbedtls_ripemd160_finish( (mbedtls_ripemd160_context *) ctx, output );
+}
+
+static void *ripemd160_ctx_alloc( void )
+{
+ void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_ripemd160_context ) );
+
+ if( ctx != NULL )
+ mbedtls_ripemd160_init( (mbedtls_ripemd160_context *) ctx );
+
+ return( ctx );
+}
+
+static void ripemd160_ctx_free( void *ctx )
+{
+ mbedtls_ripemd160_free( (mbedtls_ripemd160_context *) ctx );
+ mbedtls_free( ctx );
+}
+
+static void ripemd160_clone_wrap( void *dst, const void *src )
+{
+ mbedtls_ripemd160_clone( (mbedtls_ripemd160_context *) dst,
+ (const mbedtls_ripemd160_context *) src );
+}
+
+static void ripemd160_process_wrap( void *ctx, const unsigned char *data )
+{
+ mbedtls_ripemd160_process( (mbedtls_ripemd160_context *) ctx, data );
+}
+
+const mbedtls_md_info_t mbedtls_ripemd160_info = {
+ MBEDTLS_MD_RIPEMD160,
+ "RIPEMD160",
+ 20,
+ 64,
+ ripemd160_starts_wrap,
+ ripemd160_update_wrap,
+ ripemd160_finish_wrap,
+ mbedtls_ripemd160,
+ ripemd160_ctx_alloc,
+ ripemd160_ctx_free,
+ ripemd160_clone_wrap,
+ ripemd160_process_wrap,
+};
+
+#endif /* MBEDTLS_RIPEMD160_C */
+
+#if defined(MBEDTLS_SHA1_C)
+
+static void sha1_starts_wrap( void *ctx )
+{
+ mbedtls_sha1_starts( (mbedtls_sha1_context *) ctx );
+}
+
+static void sha1_update_wrap( void *ctx, const unsigned char *input,
+ size_t ilen )
+{
+ mbedtls_sha1_update( (mbedtls_sha1_context *) ctx, input, ilen );
+}
+
+static void sha1_finish_wrap( void *ctx, unsigned char *output )
+{
+ mbedtls_sha1_finish( (mbedtls_sha1_context *) ctx, output );
+}
+
+static void *sha1_ctx_alloc( void )
+{
+ void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_sha1_context ) );
+
+ if( ctx != NULL )
+ mbedtls_sha1_init( (mbedtls_sha1_context *) ctx );
+
+ return( ctx );
+}
+
+static void sha1_clone_wrap( void *dst, const void *src )
+{
+ mbedtls_sha1_clone( (mbedtls_sha1_context *) dst,
+ (const mbedtls_sha1_context *) src );
+}
+
+static void sha1_ctx_free( void *ctx )
+{
+ mbedtls_sha1_free( (mbedtls_sha1_context *) ctx );
+ mbedtls_free( ctx );
+}
+
+static void sha1_process_wrap( void *ctx, const unsigned char *data )
+{
+ mbedtls_sha1_process( (mbedtls_sha1_context *) ctx, data );
+}
+
+const mbedtls_md_info_t mbedtls_sha1_info = {
+ MBEDTLS_MD_SHA1,
+ "SHA1",
+ 20,
+ 64,
+ sha1_starts_wrap,
+ sha1_update_wrap,
+ sha1_finish_wrap,
+ mbedtls_sha1,
+ sha1_ctx_alloc,
+ sha1_ctx_free,
+ sha1_clone_wrap,
+ sha1_process_wrap,
+};
+
+#endif /* MBEDTLS_SHA1_C */
+
+/*
+ * Wrappers for generic message digests
+ */
+#if defined(MBEDTLS_SHA256_C)
+
+static void sha224_starts_wrap( void *ctx )
+{
+ mbedtls_sha256_starts( (mbedtls_sha256_context *) ctx, 1 );
+}
+
+static void sha224_update_wrap( void *ctx, const unsigned char *input,
+ size_t ilen )
+{
+ mbedtls_sha256_update( (mbedtls_sha256_context *) ctx, input, ilen );
+}
+
+static void sha224_finish_wrap( void *ctx, unsigned char *output )
+{
+ mbedtls_sha256_finish( (mbedtls_sha256_context *) ctx, output );
+}
+
+static void sha224_wrap( const unsigned char *input, size_t ilen,
+ unsigned char *output )
+{
+ mbedtls_sha256( input, ilen, output, 1 );
+}
+
+static void *sha224_ctx_alloc( void )
+{
+ void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_sha256_context ) );
+
+ if( ctx != NULL )
+ mbedtls_sha256_init( (mbedtls_sha256_context *) ctx );
+
+ return( ctx );
+}
+
+static void sha224_ctx_free( void *ctx )
+{
+ mbedtls_sha256_free( (mbedtls_sha256_context *) ctx );
+ mbedtls_free( ctx );
+}
+
+static void sha224_clone_wrap( void *dst, const void *src )
+{
+ mbedtls_sha256_clone( (mbedtls_sha256_context *) dst,
+ (const mbedtls_sha256_context *) src );
+}
+
+static void sha224_process_wrap( void *ctx, const unsigned char *data )
+{
+ mbedtls_sha256_process( (mbedtls_sha256_context *) ctx, data );
+}
+
+const mbedtls_md_info_t mbedtls_sha224_info = {
+ MBEDTLS_MD_SHA224,
+ "SHA224",
+ 28,
+ 64,
+ sha224_starts_wrap,
+ sha224_update_wrap,
+ sha224_finish_wrap,
+ sha224_wrap,
+ sha224_ctx_alloc,
+ sha224_ctx_free,
+ sha224_clone_wrap,
+ sha224_process_wrap,
+};
+
+static void sha256_starts_wrap( void *ctx )
+{
+ mbedtls_sha256_starts( (mbedtls_sha256_context *) ctx, 0 );
+}
+
+static void sha256_wrap( const unsigned char *input, size_t ilen,
+ unsigned char *output )
+{
+ mbedtls_sha256( input, ilen, output, 0 );
+}
+
+const mbedtls_md_info_t mbedtls_sha256_info = {
+ MBEDTLS_MD_SHA256,
+ "SHA256",
+ 32,
+ 64,
+ sha256_starts_wrap,
+ sha224_update_wrap,
+ sha224_finish_wrap,
+ sha256_wrap,
+ sha224_ctx_alloc,
+ sha224_ctx_free,
+ sha224_clone_wrap,
+ sha224_process_wrap,
+};
+
+#endif /* MBEDTLS_SHA256_C */
+
+#if defined(MBEDTLS_SHA512_C)
+
+static void sha384_starts_wrap( void *ctx )
+{
+ mbedtls_sha512_starts( (mbedtls_sha512_context *) ctx, 1 );
+}
+
+static void sha384_update_wrap( void *ctx, const unsigned char *input,
+ size_t ilen )
+{
+ mbedtls_sha512_update( (mbedtls_sha512_context *) ctx, input, ilen );
+}
+
+static void sha384_finish_wrap( void *ctx, unsigned char *output )
+{
+ mbedtls_sha512_finish( (mbedtls_sha512_context *) ctx, output );
+}
+
+static void sha384_wrap( const unsigned char *input, size_t ilen,
+ unsigned char *output )
+{
+ mbedtls_sha512( input, ilen, output, 1 );
+}
+
+static void *sha384_ctx_alloc( void )
+{
+ void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_sha512_context ) );
+
+ if( ctx != NULL )
+ mbedtls_sha512_init( (mbedtls_sha512_context *) ctx );
+
+ return( ctx );
+}
+
+static void sha384_ctx_free( void *ctx )
+{
+ mbedtls_sha512_free( (mbedtls_sha512_context *) ctx );
+ mbedtls_free( ctx );
+}
+
+static void sha384_clone_wrap( void *dst, const void *src )
+{
+ mbedtls_sha512_clone( (mbedtls_sha512_context *) dst,
+ (const mbedtls_sha512_context *) src );
+}
+
+static void sha384_process_wrap( void *ctx, const unsigned char *data )
+{
+ mbedtls_sha512_process( (mbedtls_sha512_context *) ctx, data );
+}
+
+const mbedtls_md_info_t mbedtls_sha384_info = {
+ MBEDTLS_MD_SHA384,
+ "SHA384",
+ 48,
+ 128,
+ sha384_starts_wrap,
+ sha384_update_wrap,
+ sha384_finish_wrap,
+ sha384_wrap,
+ sha384_ctx_alloc,
+ sha384_ctx_free,
+ sha384_clone_wrap,
+ sha384_process_wrap,
+};
+
+static void sha512_starts_wrap( void *ctx )
+{
+ mbedtls_sha512_starts( (mbedtls_sha512_context *) ctx, 0 );
+}
+
+static void sha512_wrap( const unsigned char *input, size_t ilen,
+ unsigned char *output )
+{
+ mbedtls_sha512( input, ilen, output, 0 );
+}
+
+const mbedtls_md_info_t mbedtls_sha512_info = {
+ MBEDTLS_MD_SHA512,
+ "SHA512",
+ 64,
+ 128,
+ sha512_starts_wrap,
+ sha384_update_wrap,
+ sha384_finish_wrap,
+ sha512_wrap,
+ sha384_ctx_alloc,
+ sha384_ctx_free,
+ sha384_clone_wrap,
+ sha384_process_wrap,
+};
+
+#endif /* MBEDTLS_SHA512_C */
+
+#endif /* MBEDTLS_MD_C */
diff --git a/backport/compat/verification/oid.c b/backport/compat/verification/oid.c
new file mode 100644
index 00000000..64753690
--- /dev/null
+++ b/backport/compat/verification/oid.c
@@ -0,0 +1,709 @@
+/**
+ * \file oid.c
+ *
+ * \brief Object Identifier (OID) database
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: GPL-2.0
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * This file is part of mbed TLS (https://tls.mbed.org)
+ */
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "mbedtls/config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#if defined(MBEDTLS_OID_C)
+
+#include "mbedtls/oid.h"
+#include "mbedtls/rsa.h"
+
+#if defined(MBEDTLS_PLATFORM_C)
+#include "mbedtls/platform.h"
+#else
+#define mbedtls_snprintf snprintf
+#endif
+
+#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C)
+#include "mbedtls/x509.h"
+#endif
+
+/*
+ * Macro to automatically add the size of #define'd OIDs
+ */
+#define ADD_LEN(s) s, MBEDTLS_OID_SIZE(s)
+
+/*
+ * Macro to generate an internal function for oid_XXX_from_asn1() (used by
+ * the other functions)
+ */
+#define FN_OID_TYPED_FROM_ASN1( TYPE_T, NAME, LIST ) \
+static const TYPE_T * oid_ ## NAME ## _from_asn1( const mbedtls_asn1_buf *oid ) \
+{ \
+ const TYPE_T *p = LIST; \
+ const mbedtls_oid_descriptor_t *cur = (const mbedtls_oid_descriptor_t *) p; \
+ if( p == NULL || oid == NULL ) return( NULL ); \
+ while( cur->asn1 != NULL ) { \
+ if( cur->asn1_len == oid->len && \
+ memcmp( cur->asn1, oid->p, oid->len ) == 0 ) { \
+ return( p ); \
+ } \
+ p++; \
+ cur = (const mbedtls_oid_descriptor_t *) p; \
+ } \
+ return( NULL ); \
+}
+
+/*
+ * Macro to generate a function for retrieving a single attribute from the
+ * descriptor of an mbedtls_oid_descriptor_t wrapper.
+ */
+#define FN_OID_GET_DESCRIPTOR_ATTR1(FN_NAME, TYPE_T, TYPE_NAME, ATTR1_TYPE, ATTR1) \
+int FN_NAME( const mbedtls_asn1_buf *oid, ATTR1_TYPE * ATTR1 ) \
+{ \
+ const TYPE_T *data = oid_ ## TYPE_NAME ## _from_asn1( oid ); \
+ if( data == NULL ) return( MBEDTLS_ERR_OID_NOT_FOUND ); \
+ *ATTR1 = data->descriptor.ATTR1; \
+ return( 0 ); \
+}
+
+/*
+ * Macro to generate a function for retrieving a single attribute from an
+ * mbedtls_oid_descriptor_t wrapper.
+ */
+#define FN_OID_GET_ATTR1(FN_NAME, TYPE_T, TYPE_NAME, ATTR1_TYPE, ATTR1) \
+int FN_NAME( const mbedtls_asn1_buf *oid, ATTR1_TYPE * ATTR1 ) \
+{ \
+ const TYPE_T *data = oid_ ## TYPE_NAME ## _from_asn1( oid ); \
+ if( data == NULL ) return( MBEDTLS_ERR_OID_NOT_FOUND ); \
+ *ATTR1 = data->ATTR1; \
+ return( 0 ); \
+}
+
+/*
+ * Macro to generate a function for retrieving two attributes from an
+ * mbedtls_oid_descriptor_t wrapper.
+ */
+#define FN_OID_GET_ATTR2(FN_NAME, TYPE_T, TYPE_NAME, ATTR1_TYPE, ATTR1, \
+ ATTR2_TYPE, ATTR2) \
+int FN_NAME( const mbedtls_asn1_buf *oid, ATTR1_TYPE * ATTR1, ATTR2_TYPE * ATTR2 ) \
+{ \
+ const TYPE_T *data = oid_ ## TYPE_NAME ## _from_asn1( oid ); \
+ if( data == NULL ) return( MBEDTLS_ERR_OID_NOT_FOUND ); \
+ *ATTR1 = data->ATTR1; \
+ *ATTR2 = data->ATTR2; \
+ return( 0 ); \
+}
+
+/*
+ * Macro to generate a function for retrieving the OID based on a single
+ * attribute from a mbedtls_oid_descriptor_t wrapper.
+ */
+#define FN_OID_GET_OID_BY_ATTR1(FN_NAME, TYPE_T, LIST, ATTR1_TYPE, ATTR1) \
+int FN_NAME( ATTR1_TYPE ATTR1, const char **oid, size_t *olen ) \
+{ \
+ const TYPE_T *cur = LIST; \
+ while( cur->descriptor.asn1 != NULL ) { \
+ if( cur->ATTR1 == ATTR1 ) { \
+ *oid = cur->descriptor.asn1; \
+ *olen = cur->descriptor.asn1_len; \
+ return( 0 ); \
+ } \
+ cur++; \
+ } \
+ return( MBEDTLS_ERR_OID_NOT_FOUND ); \
+}
+
+/*
+ * Macro to generate a function for retrieving the OID based on two
+ * attributes from a mbedtls_oid_descriptor_t wrapper.
+ */
+#define FN_OID_GET_OID_BY_ATTR2(FN_NAME, TYPE_T, LIST, ATTR1_TYPE, ATTR1, \
+ ATTR2_TYPE, ATTR2) \
+int FN_NAME( ATTR1_TYPE ATTR1, ATTR2_TYPE ATTR2, const char **oid , \
+ size_t *olen ) \
+{ \
+ const TYPE_T *cur = LIST; \
+ while( cur->descriptor.asn1 != NULL ) { \
+ if( cur->ATTR1 == ATTR1 && cur->ATTR2 == ATTR2 ) { \
+ *oid = cur->descriptor.asn1; \
+ *olen = cur->descriptor.asn1_len; \
+ return( 0 ); \
+ } \
+ cur++; \
+ } \
+ return( MBEDTLS_ERR_OID_NOT_FOUND ); \
+}
+
+#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C)
+/*
+ * For X520 attribute types
+ */
+typedef struct {
+ mbedtls_oid_descriptor_t descriptor;
+ const char *short_name;
+} oid_x520_attr_t;
+
+static const oid_x520_attr_t oid_x520_attr_type[] =
+{
+ {
+ { ADD_LEN( MBEDTLS_OID_AT_CN ), "id-at-commonName", "Common Name" },
+ "CN",
+ },
+ {
+ { ADD_LEN( MBEDTLS_OID_AT_COUNTRY ), "id-at-countryName", "Country" },
+ "C",
+ },
+ {
+ { ADD_LEN( MBEDTLS_OID_AT_LOCALITY ), "id-at-locality", "Locality" },
+ "L",
+ },
+ {
+ { ADD_LEN( MBEDTLS_OID_AT_STATE ), "id-at-state", "State" },
+ "ST",
+ },
+ {
+ { ADD_LEN( MBEDTLS_OID_AT_ORGANIZATION ),"id-at-organizationName", "Organization" },
+ "O",
+ },
+ {
+ { ADD_LEN( MBEDTLS_OID_AT_ORG_UNIT ), "id-at-organizationalUnitName", "Org Unit" },
+ "OU",
+ },
+ {
+ { ADD_LEN( MBEDTLS_OID_PKCS9_EMAIL ), "emailAddress", "E-mail address" },
+ "emailAddress",
+ },
+ {
+ { ADD_LEN( MBEDTLS_OID_AT_SERIAL_NUMBER ),"id-at-serialNumber", "Serial number" },
+ "serialNumber",
+ },
+ {
+ { ADD_LEN( MBEDTLS_OID_AT_POSTAL_ADDRESS ),"id-at-postalAddress", "Postal address" },
+ "postalAddress",
+ },
+ {
+ { ADD_LEN( MBEDTLS_OID_AT_POSTAL_CODE ), "id-at-postalCode", "Postal code" },
+ "postalCode",
+ },
+ {
+ { ADD_LEN( MBEDTLS_OID_AT_SUR_NAME ), "id-at-surName", "Surname" },
+ "SN",
+ },
+ {
+ { ADD_LEN( MBEDTLS_OID_AT_GIVEN_NAME ), "id-at-givenName", "Given name" },
+ "GN",
+ },
+ {
+ { ADD_LEN( MBEDTLS_OID_AT_INITIALS ), "id-at-initials", "Initials" },
+ "initials",
+ },
+ {
+ { ADD_LEN( MBEDTLS_OID_AT_GENERATION_QUALIFIER ), "id-at-generationQualifier", "Generation qualifier" },
+ "generationQualifier",
+ },
+ {
+ { ADD_LEN( MBEDTLS_OID_AT_TITLE ), "id-at-title", "Title" },
+ "title",
+ },
+ {
+ { ADD_LEN( MBEDTLS_OID_AT_DN_QUALIFIER ),"id-at-dnQualifier", "Distinguished Name qualifier" },
+ "dnQualifier",
+ },
+ {
+ { ADD_LEN( MBEDTLS_OID_AT_PSEUDONYM ), "id-at-pseudonym", "Pseudonym" },
+ "pseudonym",
+ },
+ {
+ { ADD_LEN( MBEDTLS_OID_DOMAIN_COMPONENT ), "id-domainComponent", "Domain component" },
+ "DC",
+ },
+ {
+ { ADD_LEN( MBEDTLS_OID_AT_UNIQUE_IDENTIFIER ), "id-at-uniqueIdentifier", "Unique Identifier" },
+ "uniqueIdentifier",
+ },
+ {
+ { NULL, 0, NULL, NULL },
+ NULL,
+ }
+};
+
+FN_OID_TYPED_FROM_ASN1(oid_x520_attr_t, x520_attr, oid_x520_attr_type)
+FN_OID_GET_ATTR1(mbedtls_oid_get_attr_short_name, oid_x520_attr_t, x520_attr, const char *, short_name)
+
+/*
+ * For X509 extensions
+ */
+typedef struct {
+ mbedtls_oid_descriptor_t descriptor;
+ int ext_type;
+} oid_x509_ext_t;
+
+static const oid_x509_ext_t oid_x509_ext[] =
+{
+ {
+ { ADD_LEN( MBEDTLS_OID_BASIC_CONSTRAINTS ), "id-ce-basicConstraints", "Basic Constraints" },
+ MBEDTLS_X509_EXT_BASIC_CONSTRAINTS,
+ },
+ {
+ { ADD_LEN( MBEDTLS_OID_KEY_USAGE ), "id-ce-keyUsage", "Key Usage" },
+ MBEDTLS_X509_EXT_KEY_USAGE,
+ },
+ {
+ { ADD_LEN( MBEDTLS_OID_EXTENDED_KEY_USAGE ), "id-ce-extKeyUsage", "Extended Key Usage" },
+ MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE,
+ },
+ {
+ { ADD_LEN( MBEDTLS_OID_SUBJECT_ALT_NAME ), "id-ce-subjectAltName", "Subject Alt Name" },
+ MBEDTLS_X509_EXT_SUBJECT_ALT_NAME,
+ },
+ {
+ { ADD_LEN( MBEDTLS_OID_NS_CERT_TYPE ), "id-netscape-certtype", "Netscape Certificate Type" },
+ MBEDTLS_X509_EXT_NS_CERT_TYPE,
+ },
+ {
+ { NULL, 0, NULL, NULL },
+ 0,
+ },
+};
+
+FN_OID_TYPED_FROM_ASN1(oid_x509_ext_t, x509_ext, oid_x509_ext)
+FN_OID_GET_ATTR1(mbedtls_oid_get_x509_ext_type, oid_x509_ext_t, x509_ext, int, ext_type)
+
+static const mbedtls_oid_descriptor_t oid_ext_key_usage[] =
+{
+ { ADD_LEN( MBEDTLS_OID_SERVER_AUTH ), "id-kp-serverAuth", "TLS Web Server Authentication" },
+ { ADD_LEN( MBEDTLS_OID_CLIENT_AUTH ), "id-kp-clientAuth", "TLS Web Client Authentication" },
+ { ADD_LEN( MBEDTLS_OID_CODE_SIGNING ), "id-kp-codeSigning", "Code Signing" },
+ { ADD_LEN( MBEDTLS_OID_EMAIL_PROTECTION ), "id-kp-emailProtection", "E-mail Protection" },
+ { ADD_LEN( MBEDTLS_OID_TIME_STAMPING ), "id-kp-timeStamping", "Time Stamping" },
+ { ADD_LEN( MBEDTLS_OID_OCSP_SIGNING ), "id-kp-OCSPSigning", "OCSP Signing" },
+ { NULL, 0, NULL, NULL },
+};
+
+FN_OID_TYPED_FROM_ASN1(mbedtls_oid_descriptor_t, ext_key_usage, oid_ext_key_usage)
+FN_OID_GET_ATTR1(mbedtls_oid_get_extended_key_usage, mbedtls_oid_descriptor_t, ext_key_usage, const char *, description)
+#endif /* MBEDTLS_X509_USE_C || MBEDTLS_X509_CREATE_C */
+
+#if defined(MBEDTLS_MD_C)
+/*
+ * For SignatureAlgorithmIdentifier
+ */
+typedef struct {
+ mbedtls_oid_descriptor_t descriptor;
+ mbedtls_md_type_t md_alg;
+ mbedtls_pk_type_t pk_alg;
+} oid_sig_alg_t;
+
+static const oid_sig_alg_t oid_sig_alg[] =
+{
+#if defined(MBEDTLS_RSA_C)
+#if defined(MBEDTLS_MD2_C)
+ {
+ { ADD_LEN( MBEDTLS_OID_PKCS1_MD2 ), "md2WithRSAEncryption", "RSA with MD2" },
+ MBEDTLS_MD_MD2, MBEDTLS_PK_RSA,
+ },
+#endif /* MBEDTLS_MD2_C */
+#if defined(MBEDTLS_MD4_C)
+ {
+ { ADD_LEN( MBEDTLS_OID_PKCS1_MD4 ), "md4WithRSAEncryption", "RSA with MD4" },
+ MBEDTLS_MD_MD4, MBEDTLS_PK_RSA,
+ },
+#endif /* MBEDTLS_MD4_C */
+#if defined(MBEDTLS_MD5_C)
+ {
+ { ADD_LEN( MBEDTLS_OID_PKCS1_MD5 ), "md5WithRSAEncryption", "RSA with MD5" },
+ MBEDTLS_MD_MD5, MBEDTLS_PK_RSA,
+ },
+#endif /* MBEDTLS_MD5_C */
+#if defined(MBEDTLS_SHA1_C)
+ {
+ { ADD_LEN( MBEDTLS_OID_PKCS1_SHA1 ), "sha-1WithRSAEncryption", "RSA with SHA1" },
+ MBEDTLS_MD_SHA1, MBEDTLS_PK_RSA,
+ },
+#endif /* MBEDTLS_SHA1_C */
+#if defined(MBEDTLS_SHA256_C)
+ {
+ { ADD_LEN( MBEDTLS_OID_PKCS1_SHA224 ), "sha224WithRSAEncryption", "RSA with SHA-224" },
+ MBEDTLS_MD_SHA224, MBEDTLS_PK_RSA,
+ },
+ {
+ { ADD_LEN( MBEDTLS_OID_PKCS1_SHA256 ), "sha256WithRSAEncryption", "RSA with SHA-256" },
+ MBEDTLS_MD_SHA256, MBEDTLS_PK_RSA,
+ },
+#endif /* MBEDTLS_SHA256_C */
+#if defined(MBEDTLS_SHA512_C)
+ {
+ { ADD_LEN( MBEDTLS_OID_PKCS1_SHA384 ), "sha384WithRSAEncryption", "RSA with SHA-384" },
+ MBEDTLS_MD_SHA384, MBEDTLS_PK_RSA,
+ },
+ {
+ { ADD_LEN( MBEDTLS_OID_PKCS1_SHA512 ), "sha512WithRSAEncryption", "RSA with SHA-512" },
+ MBEDTLS_MD_SHA512, MBEDTLS_PK_RSA,
+ },
+#endif /* MBEDTLS_SHA512_C */
+#if defined(MBEDTLS_SHA1_C)
+ {
+ { ADD_LEN( MBEDTLS_OID_RSA_SHA_OBS ), "sha-1WithRSAEncryption", "RSA with SHA1" },
+ MBEDTLS_MD_SHA1, MBEDTLS_PK_RSA,
+ },
+#endif /* MBEDTLS_SHA1_C */
+#endif /* MBEDTLS_RSA_C */
+#if defined(MBEDTLS_ECDSA_C)
+#if defined(MBEDTLS_SHA1_C)
+ {
+ { ADD_LEN( MBEDTLS_OID_ECDSA_SHA1 ), "ecdsa-with-SHA1", "ECDSA with SHA1" },
+ MBEDTLS_MD_SHA1, MBEDTLS_PK_ECDSA,
+ },
+#endif /* MBEDTLS_SHA1_C */
+#if defined(MBEDTLS_SHA256_C)
+ {
+ { ADD_LEN( MBEDTLS_OID_ECDSA_SHA224 ), "ecdsa-with-SHA224", "ECDSA with SHA224" },
+ MBEDTLS_MD_SHA224, MBEDTLS_PK_ECDSA,
+ },
+ {
+ { ADD_LEN( MBEDTLS_OID_ECDSA_SHA256 ), "ecdsa-with-SHA256", "ECDSA with SHA256" },
+ MBEDTLS_MD_SHA256, MBEDTLS_PK_ECDSA,
+ },
+#endif /* MBEDTLS_SHA256_C */
+#if defined(MBEDTLS_SHA512_C)
+ {
+ { ADD_LEN( MBEDTLS_OID_ECDSA_SHA384 ), "ecdsa-with-SHA384", "ECDSA with SHA384" },
+ MBEDTLS_MD_SHA384, MBEDTLS_PK_ECDSA,
+ },
+ {
+ { ADD_LEN( MBEDTLS_OID_ECDSA_SHA512 ), "ecdsa-with-SHA512", "ECDSA with SHA512" },
+ MBEDTLS_MD_SHA512, MBEDTLS_PK_ECDSA,
+ },
+#endif /* MBEDTLS_SHA512_C */
+#endif /* MBEDTLS_ECDSA_C */
+#if defined(MBEDTLS_RSA_C)
+ {
+ { ADD_LEN( MBEDTLS_OID_RSASSA_PSS ), "RSASSA-PSS", "RSASSA-PSS" },
+ MBEDTLS_MD_NONE, MBEDTLS_PK_RSASSA_PSS,
+ },
+#endif /* MBEDTLS_RSA_C */
+ {
+ { NULL, 0, NULL, NULL },
+ MBEDTLS_MD_NONE, MBEDTLS_PK_NONE,
+ },
+};
+
+FN_OID_TYPED_FROM_ASN1(oid_sig_alg_t, sig_alg, oid_sig_alg)
+FN_OID_GET_DESCRIPTOR_ATTR1(mbedtls_oid_get_sig_alg_desc, oid_sig_alg_t, sig_alg, const char *, description)
+FN_OID_GET_ATTR2(mbedtls_oid_get_sig_alg, oid_sig_alg_t, sig_alg, mbedtls_md_type_t, md_alg, mbedtls_pk_type_t, pk_alg)
+FN_OID_GET_OID_BY_ATTR2(mbedtls_oid_get_oid_by_sig_alg, oid_sig_alg_t, oid_sig_alg, mbedtls_pk_type_t, pk_alg, mbedtls_md_type_t, md_alg)
+#endif /* MBEDTLS_MD_C */
+
+/*
+ * For PublicKeyInfo (PKCS1, RFC 5480)
+ */
+typedef struct {
+ mbedtls_oid_descriptor_t descriptor;
+ mbedtls_pk_type_t pk_alg;
+} oid_pk_alg_t;
+
+static const oid_pk_alg_t oid_pk_alg[] =
+{
+ {
+ { ADD_LEN( MBEDTLS_OID_PKCS1_RSA ), "rsaEncryption", "RSA" },
+ MBEDTLS_PK_RSA,
+ },
+ {
+ { ADD_LEN( MBEDTLS_OID_EC_ALG_UNRESTRICTED ), "id-ecPublicKey", "Generic EC key" },
+ MBEDTLS_PK_ECKEY,
+ },
+ {
+ { ADD_LEN( MBEDTLS_OID_EC_ALG_ECDH ), "id-ecDH", "EC key for ECDH" },
+ MBEDTLS_PK_ECKEY_DH,
+ },
+ {
+ { NULL, 0, NULL, NULL },
+ MBEDTLS_PK_NONE,
+ },
+};
+
+FN_OID_TYPED_FROM_ASN1(oid_pk_alg_t, pk_alg, oid_pk_alg)
+FN_OID_GET_ATTR1(mbedtls_oid_get_pk_alg, oid_pk_alg_t, pk_alg, mbedtls_pk_type_t, pk_alg)
+FN_OID_GET_OID_BY_ATTR1(mbedtls_oid_get_oid_by_pk_alg, oid_pk_alg_t, oid_pk_alg, mbedtls_pk_type_t, pk_alg)
+
+#if defined(MBEDTLS_ECP_C)
+/*
+ * For namedCurve (RFC 5480)
+ */
+typedef struct {
+ mbedtls_oid_descriptor_t descriptor;
+ mbedtls_ecp_group_id grp_id;
+} oid_ecp_grp_t;
+
+static const oid_ecp_grp_t oid_ecp_grp[] =
+{
+#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED)
+ {
+ { ADD_LEN( MBEDTLS_OID_EC_GRP_SECP192R1 ), "secp192r1", "secp192r1" },
+ MBEDTLS_ECP_DP_SECP192R1,
+ },
+#endif /* MBEDTLS_ECP_DP_SECP192R1_ENABLED */
+#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED)
+ {
+ { ADD_LEN( MBEDTLS_OID_EC_GRP_SECP224R1 ), "secp224r1", "secp224r1" },
+ MBEDTLS_ECP_DP_SECP224R1,
+ },
+#endif /* MBEDTLS_ECP_DP_SECP224R1_ENABLED */
+#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED)
+ {
+ { ADD_LEN( MBEDTLS_OID_EC_GRP_SECP256R1 ), "secp256r1", "secp256r1" },
+ MBEDTLS_ECP_DP_SECP256R1,
+ },
+#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED */
+#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED)
+ {
+ { ADD_LEN( MBEDTLS_OID_EC_GRP_SECP384R1 ), "secp384r1", "secp384r1" },
+ MBEDTLS_ECP_DP_SECP384R1,
+ },
+#endif /* MBEDTLS_ECP_DP_SECP384R1_ENABLED */
+#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED)
+ {
+ { ADD_LEN( MBEDTLS_OID_EC_GRP_SECP521R1 ), "secp521r1", "secp521r1" },
+ MBEDTLS_ECP_DP_SECP521R1,
+ },
+#endif /* MBEDTLS_ECP_DP_SECP521R1_ENABLED */
+#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED)
+ {
+ { ADD_LEN( MBEDTLS_OID_EC_GRP_SECP192K1 ), "secp192k1", "secp192k1" },
+ MBEDTLS_ECP_DP_SECP192K1,
+ },
+#endif /* MBEDTLS_ECP_DP_SECP192K1_ENABLED */
+#if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED)
+ {
+ { ADD_LEN( MBEDTLS_OID_EC_GRP_SECP224K1 ), "secp224k1", "secp224k1" },
+ MBEDTLS_ECP_DP_SECP224K1,
+ },
+#endif /* MBEDTLS_ECP_DP_SECP224K1_ENABLED */
+#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED)
+ {
+ { ADD_LEN( MBEDTLS_OID_EC_GRP_SECP256K1 ), "secp256k1", "secp256k1" },
+ MBEDTLS_ECP_DP_SECP256K1,
+ },
+#endif /* MBEDTLS_ECP_DP_SECP256K1_ENABLED */
+#if defined(MBEDTLS_ECP_DP_BP256R1_ENABLED)
+ {
+ { ADD_LEN( MBEDTLS_OID_EC_GRP_BP256R1 ), "brainpoolP256r1","brainpool256r1" },
+ MBEDTLS_ECP_DP_BP256R1,
+ },
+#endif /* MBEDTLS_ECP_DP_BP256R1_ENABLED */
+#if defined(MBEDTLS_ECP_DP_BP384R1_ENABLED)
+ {
+ { ADD_LEN( MBEDTLS_OID_EC_GRP_BP384R1 ), "brainpoolP384r1","brainpool384r1" },
+ MBEDTLS_ECP_DP_BP384R1,
+ },
+#endif /* MBEDTLS_ECP_DP_BP384R1_ENABLED */
+#if defined(MBEDTLS_ECP_DP_BP512R1_ENABLED)
+ {
+ { ADD_LEN( MBEDTLS_OID_EC_GRP_BP512R1 ), "brainpoolP512r1","brainpool512r1" },
+ MBEDTLS_ECP_DP_BP512R1,
+ },
+#endif /* MBEDTLS_ECP_DP_BP512R1_ENABLED */
+ {
+ { NULL, 0, NULL, NULL },
+ MBEDTLS_ECP_DP_NONE,
+ },
+};
+
+FN_OID_TYPED_FROM_ASN1(oid_ecp_grp_t, grp_id, oid_ecp_grp)
+FN_OID_GET_ATTR1(mbedtls_oid_get_ec_grp, oid_ecp_grp_t, grp_id, mbedtls_ecp_group_id, grp_id)
+FN_OID_GET_OID_BY_ATTR1(mbedtls_oid_get_oid_by_ec_grp, oid_ecp_grp_t, oid_ecp_grp, mbedtls_ecp_group_id, grp_id)
+#endif /* MBEDTLS_ECP_C */
+
+#if defined(MBEDTLS_CIPHER_C)
+/*
+ * For PKCS#5 PBES2 encryption algorithm
+ */
+typedef struct {
+ mbedtls_oid_descriptor_t descriptor;
+ mbedtls_cipher_type_t cipher_alg;
+} oid_cipher_alg_t;
+
+static const oid_cipher_alg_t oid_cipher_alg[] =
+{
+ {
+ { ADD_LEN( MBEDTLS_OID_DES_CBC ), "desCBC", "DES-CBC" },
+ MBEDTLS_CIPHER_DES_CBC,
+ },
+ {
+ { ADD_LEN( MBEDTLS_OID_DES_EDE3_CBC ), "des-ede3-cbc", "DES-EDE3-CBC" },
+ MBEDTLS_CIPHER_DES_EDE3_CBC,
+ },
+ {
+ { NULL, 0, NULL, NULL },
+ MBEDTLS_CIPHER_NONE,
+ },
+};
+
+FN_OID_TYPED_FROM_ASN1(oid_cipher_alg_t, cipher_alg, oid_cipher_alg)
+FN_OID_GET_ATTR1(mbedtls_oid_get_cipher_alg, oid_cipher_alg_t, cipher_alg, mbedtls_cipher_type_t, cipher_alg)
+#endif /* MBEDTLS_CIPHER_C */
+
+#if defined(MBEDTLS_MD_C)
+/*
+ * For digestAlgorithm
+ */
+typedef struct {
+ mbedtls_oid_descriptor_t descriptor;
+ mbedtls_md_type_t md_alg;
+} oid_md_alg_t;
+
+static const oid_md_alg_t oid_md_alg[] =
+{
+#if defined(MBEDTLS_MD2_C)
+ {
+ { ADD_LEN( MBEDTLS_OID_DIGEST_ALG_MD2 ), "id-md2", "MD2" },
+ MBEDTLS_MD_MD2,
+ },
+#endif /* MBEDTLS_MD2_C */
+#if defined(MBEDTLS_MD4_C)
+ {
+ { ADD_LEN( MBEDTLS_OID_DIGEST_ALG_MD4 ), "id-md4", "MD4" },
+ MBEDTLS_MD_MD4,
+ },
+#endif /* MBEDTLS_MD4_C */
+#if defined(MBEDTLS_MD5_C)
+ {
+ { ADD_LEN( MBEDTLS_OID_DIGEST_ALG_MD5 ), "id-md5", "MD5" },
+ MBEDTLS_MD_MD5,
+ },
+#endif /* MBEDTLS_MD5_C */
+#if defined(MBEDTLS_SHA1_C)
+ {
+ { ADD_LEN( MBEDTLS_OID_DIGEST_ALG_SHA1 ), "id-sha1", "SHA-1" },
+ MBEDTLS_MD_SHA1,
+ },
+#endif /* MBEDTLS_SHA1_C */
+#if defined(MBEDTLS_SHA256_C)
+ {
+ { ADD_LEN( MBEDTLS_OID_DIGEST_ALG_SHA224 ), "id-sha224", "SHA-224" },
+ MBEDTLS_MD_SHA224,
+ },
+ {
+ { ADD_LEN( MBEDTLS_OID_DIGEST_ALG_SHA256 ), "id-sha256", "SHA-256" },
+ MBEDTLS_MD_SHA256,
+ },
+#endif /* MBEDTLS_SHA256_C */
+#if defined(MBEDTLS_SHA512_C)
+ {
+ { ADD_LEN( MBEDTLS_OID_DIGEST_ALG_SHA384 ), "id-sha384", "SHA-384" },
+ MBEDTLS_MD_SHA384,
+ },
+ {
+ { ADD_LEN( MBEDTLS_OID_DIGEST_ALG_SHA512 ), "id-sha512", "SHA-512" },
+ MBEDTLS_MD_SHA512,
+ },
+#endif /* MBEDTLS_SHA512_C */
+ {
+ { NULL, 0, NULL, NULL },
+ MBEDTLS_MD_NONE,
+ },
+};
+
+FN_OID_TYPED_FROM_ASN1(oid_md_alg_t, md_alg, oid_md_alg)
+FN_OID_GET_ATTR1(mbedtls_oid_get_md_alg, oid_md_alg_t, md_alg, mbedtls_md_type_t, md_alg)
+FN_OID_GET_OID_BY_ATTR1(mbedtls_oid_get_oid_by_md, oid_md_alg_t, oid_md_alg, mbedtls_md_type_t, md_alg)
+#endif /* MBEDTLS_MD_C */
+
+#if defined(MBEDTLS_PKCS12_C)
+/*
+ * For PKCS#12 PBEs
+ */
+typedef struct {
+ mbedtls_oid_descriptor_t descriptor;
+ mbedtls_md_type_t md_alg;
+ mbedtls_cipher_type_t cipher_alg;
+} oid_pkcs12_pbe_alg_t;
+
+static const oid_pkcs12_pbe_alg_t oid_pkcs12_pbe_alg[] =
+{
+ {
+ { ADD_LEN( MBEDTLS_OID_PKCS12_PBE_SHA1_DES3_EDE_CBC ), "pbeWithSHAAnd3-KeyTripleDES-CBC", "PBE with SHA1 and 3-Key 3DES" },
+ MBEDTLS_MD_SHA1, MBEDTLS_CIPHER_DES_EDE3_CBC,
+ },
+ {
+ { ADD_LEN( MBEDTLS_OID_PKCS12_PBE_SHA1_DES2_EDE_CBC ), "pbeWithSHAAnd2-KeyTripleDES-CBC", "PBE with SHA1 and 2-Key 3DES" },
+ MBEDTLS_MD_SHA1, MBEDTLS_CIPHER_DES_EDE_CBC,
+ },
+ {
+ { NULL, 0, NULL, NULL },
+ MBEDTLS_MD_NONE, MBEDTLS_CIPHER_NONE,
+ },
+};
+
+FN_OID_TYPED_FROM_ASN1(oid_pkcs12_pbe_alg_t, pkcs12_pbe_alg, oid_pkcs12_pbe_alg)
+FN_OID_GET_ATTR2(mbedtls_oid_get_pkcs12_pbe_alg, oid_pkcs12_pbe_alg_t, pkcs12_pbe_alg, mbedtls_md_type_t, md_alg, mbedtls_cipher_type_t, cipher_alg)
+#endif /* MBEDTLS_PKCS12_C */
+
+#define OID_SAFE_SNPRINTF \
+ do { \
+ if( ret < 0 || (size_t) ret >= n ) \
+ return( MBEDTLS_ERR_OID_BUF_TOO_SMALL ); \
+ \
+ n -= (size_t) ret; \
+ p += (size_t) ret; \
+ } while( 0 )
+
+/* Return the x.y.z.... style numeric string for the given OID */
+int mbedtls_oid_get_numeric_string( char *buf, size_t size,
+ const mbedtls_asn1_buf *oid )
+{
+ int ret;
+ size_t i, n;
+ unsigned int value;
+ char *p;
+
+ p = buf;
+ n = size;
+
+ /* First byte contains first two dots */
+ if( oid->len > 0 )
+ {
+ ret = mbedtls_snprintf( p, n, "%d.%d", oid->p[0] / 40, oid->p[0] % 40 );
+ OID_SAFE_SNPRINTF;
+ }
+
+ value = 0;
+ for( i = 1; i < oid->len; i++ )
+ {
+ /* Prevent overflow in value. */
+ if( ( ( value << 7 ) >> 7 ) != value )
+ return( MBEDTLS_ERR_OID_BUF_TOO_SMALL );
+
+ value <<= 7;
+ value += oid->p[i] & 0x7F;
+
+ if( !( oid->p[i] & 0x80 ) )
+ {
+ /* Last byte */
+ ret = mbedtls_snprintf( p, n, ".%d", value );
+ OID_SAFE_SNPRINTF;
+ value = 0;
+ }
+ }
+
+ return( (int) ( size - n ) );
+}
+
+#endif /* MBEDTLS_OID_C */
diff --git a/backport/compat/verification/pkcs7-asn1.c b/backport/compat/verification/pkcs7-asn1.c
new file mode 100644
index 00000000..9073fd94
--- /dev/null
+++ b/backport/compat/verification/pkcs7-asn1.c
@@ -0,0 +1,355 @@
+/*
+ * Automatically generated by asn1_compiler. Do not edit
+ *
+ * ASN.1 parser for pkcs7
+ */
+#include <linux/asn1_ber_bytecode.h>
+#include "pkcs7-asn1.h"
+
+enum pkcs7_actions {
+ ACT_pkcs7_check_content_type = 0,
+ ACT_pkcs7_extract_cert = 1,
+ ACT_pkcs7_note_OID = 2,
+ ACT_pkcs7_note_certificate_list = 3,
+ ACT_pkcs7_note_content = 4,
+ ACT_pkcs7_note_data = 5,
+ ACT_pkcs7_note_signed_info = 6,
+ ACT_pkcs7_note_signeddata_version = 7,
+ ACT_pkcs7_note_signerinfo_version = 8,
+ ACT_pkcs7_sig_note_authenticated_attr = 9,
+ ACT_pkcs7_sig_note_digest_algo = 10,
+ ACT_pkcs7_sig_note_issuer = 11,
+ ACT_pkcs7_sig_note_pkey_algo = 12,
+ ACT_pkcs7_sig_note_serial = 13,
+ ACT_pkcs7_sig_note_set_of_authattrs = 14,
+ ACT_pkcs7_sig_note_signature = 15,
+ ACT_pkcs7_sig_note_skid = 16,
+ NR__pkcs7_actions = 17
+};
+
+static const asn1_action_t pkcs7_action_table[NR__pkcs7_actions] = {
+ [ 0] = pkcs7_check_content_type,
+ [ 1] = pkcs7_extract_cert,
+ [ 2] = pkcs7_note_OID,
+ [ 3] = pkcs7_note_certificate_list,
+ [ 4] = pkcs7_note_content,
+ [ 5] = pkcs7_note_data,
+ [ 6] = pkcs7_note_signed_info,
+ [ 7] = pkcs7_note_signeddata_version,
+ [ 8] = pkcs7_note_signerinfo_version,
+ [ 9] = pkcs7_sig_note_authenticated_attr,
+ [ 10] = pkcs7_sig_note_digest_algo,
+ [ 11] = pkcs7_sig_note_issuer,
+ [ 12] = pkcs7_sig_note_pkey_algo,
+ [ 13] = pkcs7_sig_note_serial,
+ [ 14] = pkcs7_sig_note_set_of_authattrs,
+ [ 15] = pkcs7_sig_note_signature,
+ [ 16] = pkcs7_sig_note_skid,
+};
+
+static const unsigned char pkcs7_machine[] = {
+ // PKCS7ContentInfo
+ [ 0] = ASN1_OP_MATCH,
+ [ 1] = _tag(UNIV, CONS, SEQ),
+ // ContentType
+ [ 2] = ASN1_OP_MATCH_ACT,
+ [ 3] = _tag(UNIV, PRIM, OID),
+ [ 4] = _action(ACT_pkcs7_note_OID),
+ [ 5] = ASN1_OP_ACT,
+ [ 6] = _action(ACT_pkcs7_check_content_type),
+ [ 7] = ASN1_OP_MATCH_JUMP_OR_SKIP, // content
+ [ 8] = _tagn(CONT, CONS, 0),
+ [ 9] = _jump_target(12),
+ [ 10] = ASN1_OP_END_SEQ,
+ [ 11] = ASN1_OP_COMPLETE,
+
+ // SignedData
+ [ 12] = ASN1_OP_MATCH,
+ [ 13] = _tag(UNIV, CONS, SEQ),
+ [ 14] = ASN1_OP_MATCH_ACT, // version
+ [ 15] = _tag(UNIV, PRIM, INT),
+ [ 16] = _action(ACT_pkcs7_note_signeddata_version),
+ // DigestAlgorithmIdentifiers
+ [ 17] = ASN1_OP_MATCH_JUMP_OR_SKIP, // daSet
+ [ 18] = _tag(UNIV, CONS, SET),
+ [ 19] = _jump_target(61),
+ [ 20] = ASN1_OP_COND_MATCH_JUMP_OR_SKIP, // daSequence
+ [ 21] = _tag(UNIV, CONS, SEQ),
+ [ 22] = _jump_target(67),
+ [ 23] = ASN1_OP_COND_FAIL,
+ // ContentInfo
+ [ 24] = ASN1_OP_MATCH,
+ [ 25] = _tag(UNIV, CONS, SEQ),
+ // ContentType
+ [ 26] = ASN1_OP_MATCH_ACT,
+ [ 27] = _tag(UNIV, PRIM, OID),
+ [ 28] = _action(ACT_pkcs7_note_OID),
+ [ 29] = ASN1_OP_ACT,
+ [ 30] = _action(ACT_pkcs7_note_OID),
+ [ 31] = ASN1_OP_MATCH_JUMP_OR_SKIP, // content
+ [ 32] = _tagn(CONT, CONS, 0),
+ [ 33] = _jump_target(73),
+ [ 34] = ASN1_OP_END_SEQ,
+ [ 35] = ASN1_OP_ACT,
+ [ 36] = _action(ACT_pkcs7_note_content),
+ // ExtendedCertificatesAndCertificates
+ [ 37] = ASN1_OP_MATCH_JUMP_OR_SKIP, // certSet
+ [ 38] = _tagn(CONT, CONS, 0),
+ [ 39] = _jump_target(77), // --> ExtendedCertificatesAndCertificates
+ // Certificates
+ [ 40] = ASN1_OP_COND_MATCH_JUMP_OR_SKIP, // certSequence
+ [ 41] = _tagn(CONT, CONS, 2),
+ [ 42] = _jump_target(85), // --> Certificates
+ [ 43] = ASN1_OP_ACT,
+ [ 44] = _action(ACT_pkcs7_note_certificate_list),
+ // CertificateRevocationLists
+ [ 45] = ASN1_OP_MATCH_JUMP_OR_SKIP, // crlSet
+ [ 46] = _tagn(CONT, CONS, 1),
+ [ 47] = _jump_target(90), // --> CertificateRevocationLists
+ // CRLSequence
+ [ 48] = ASN1_OP_COND_MATCH_JUMP_OR_SKIP, // crlSequence
+ [ 49] = _tagn(CONT, CONS, 3),
+ [ 50] = _jump_target(96), // --> CRLSequence
+ // SignerInfos
+ [ 51] = ASN1_OP_MATCH_JUMP_OR_SKIP, // siSet
+ [ 52] = _tag(UNIV, CONS, SET),
+ [ 53] = _jump_target(102),
+ [ 54] = ASN1_OP_COND_MATCH_JUMP_OR_SKIP, // siSequence
+ [ 55] = _tag(UNIV, CONS, SEQ),
+ [ 56] = _jump_target(108),
+ [ 57] = ASN1_OP_COND_FAIL,
+ [ 58] = ASN1_OP_END_SEQ,
+ [ 59] = ASN1_OP_END_SEQ,
+ [ 60] = ASN1_OP_RETURN,
+
+ // DigestAlgorithmIdentifier
+ [ 61] = ASN1_OP_MATCH_JUMP,
+ [ 62] = _tag(UNIV, CONS, SEQ),
+ [ 63] = _jump_target(114), // --> DigestAlgorithmIdentifier
+ [ 64] = ASN1_OP_END_SET_OF,
+ [ 65] = _jump_target(61),
+ [ 66] = ASN1_OP_RETURN,
+
+ // DigestAlgorithmIdentifier
+ [ 67] = ASN1_OP_MATCH_JUMP,
+ [ 68] = _tag(UNIV, CONS, SEQ),
+ [ 69] = _jump_target(114), // --> DigestAlgorithmIdentifier
+ [ 70] = ASN1_OP_END_SEQ_OF,
+ [ 71] = _jump_target(67),
+ [ 72] = ASN1_OP_RETURN,
+
+ // Data
+ [ 73] = ASN1_OP_MATCH_ANY_ACT,
+ [ 74] = _action(ACT_pkcs7_note_data),
+ [ 75] = ASN1_OP_END_SEQ,
+ [ 76] = ASN1_OP_RETURN,
+
+ // ExtendedCertificateOrCertificate
+ // Certificate
+ [ 77] = ASN1_OP_MATCH_ANY_ACT_OR_SKIP,
+ [ 78] = _action(ACT_pkcs7_extract_cert),
+ // ExtendedCertificate
+ // Certificate
+ [ 79] = ASN1_OP_COND_MATCH_ANY_ACT_OR_SKIP,
+ [ 80] = _action(ACT_pkcs7_extract_cert),
+ [ 81] = ASN1_OP_COND_FAIL,
+ [ 82] = ASN1_OP_END_SET_OF,
+ [ 83] = _jump_target(77),
+ [ 84] = ASN1_OP_RETURN,
+
+ // Certificate
+ [ 85] = ASN1_OP_MATCH_ANY_ACT,
+ [ 86] = _action(ACT_pkcs7_extract_cert),
+ [ 87] = ASN1_OP_END_SEQ_OF,
+ [ 88] = _jump_target(85),
+ [ 89] = ASN1_OP_RETURN,
+
+ // CertificateList
+ [ 90] = ASN1_OP_MATCH_JUMP,
+ [ 91] = _tag(UNIV, CONS, SEQ),
+ [ 92] = _jump_target(120), // --> CertificateList
+ [ 93] = ASN1_OP_END_SET_OF,
+ [ 94] = _jump_target(90),
+ [ 95] = ASN1_OP_RETURN,
+
+ // CertificateList
+ [ 96] = ASN1_OP_MATCH_JUMP,
+ [ 97] = _tag(UNIV, CONS, SEQ),
+ [ 98] = _jump_target(120), // --> CertificateList
+ [ 99] = ASN1_OP_END_SEQ_OF,
+ [ 100] = _jump_target(96),
+ [ 101] = ASN1_OP_RETURN,
+
+ // SignerInfo
+ [ 102] = ASN1_OP_MATCH_JUMP,
+ [ 103] = _tag(UNIV, CONS, SEQ),
+ [ 104] = _jump_target(125), // --> SignerInfo
+ [ 105] = ASN1_OP_END_SET_OF,
+ [ 106] = _jump_target(102),
+ [ 107] = ASN1_OP_RETURN,
+
+ // SignerInfo
+ [ 108] = ASN1_OP_MATCH_JUMP,
+ [ 109] = _tag(UNIV, CONS, SEQ),
+ [ 110] = _jump_target(125), // --> SignerInfo
+ [ 111] = ASN1_OP_END_SEQ_OF,
+ [ 112] = _jump_target(108),
+ [ 113] = ASN1_OP_RETURN,
+
+ [ 114] = ASN1_OP_MATCH_ACT, // algorithm
+ [ 115] = _tag(UNIV, PRIM, OID),
+ [ 116] = _action(ACT_pkcs7_note_OID),
+ [ 117] = ASN1_OP_MATCH_ANY_OR_SKIP, // parameters
+ [ 118] = ASN1_OP_END_SEQ,
+ [ 119] = ASN1_OP_RETURN,
+
+ // Certificate
+ [ 120] = ASN1_OP_MATCH_ANY_ACT,
+ [ 121] = _action(ACT_pkcs7_extract_cert),
+ [ 122] = ASN1_OP_END_SEQ_OF,
+ [ 123] = _jump_target(120),
+ [ 124] = ASN1_OP_RETURN,
+
+ [ 125] = ASN1_OP_MATCH_ACT, // version
+ [ 126] = _tag(UNIV, PRIM, INT),
+ [ 127] = _action(ACT_pkcs7_note_signerinfo_version),
+ // SignerIdentifier
+ // IssuerAndSerialNumber
+ [ 128] = ASN1_OP_MATCH_JUMP_OR_SKIP, // issuerAndSerialNumber
+ [ 129] = _tag(UNIV, CONS, SEQ),
+ [ 130] = _jump_target(169), // --> IssuerAndSerialNumber
+ // SubjectKeyIdentifier
+ [ 131] = ASN1_OP_COND_MATCH_ACT_OR_SKIP, // subjectKeyIdentifier
+ [ 132] = _tagn(CONT, PRIM, 0),
+ [ 133] = _action(ACT_pkcs7_sig_note_skid),
+ [ 134] = ASN1_OP_COND_FAIL,
+ // DigestAlgorithmIdentifier
+ [ 135] = ASN1_OP_MATCH_JUMP,
+ [ 136] = _tag(UNIV, CONS, SEQ),
+ [ 137] = _jump_target(114), // --> DigestAlgorithmIdentifier
+ [ 138] = ASN1_OP_ACT,
+ [ 139] = _action(ACT_pkcs7_sig_note_digest_algo),
+ // SetOfAuthenticatedAttribute
+ [ 140] = ASN1_OP_MATCH_JUMP_OR_SKIP, // aaSet
+ [ 141] = _tagn(CONT, CONS, 0),
+ [ 142] = _jump_target(192), // --> SetOfAuthenticatedAttribute
+ [ 143] = ASN1_OP_MAYBE_ACT,
+ [ 144] = _action(ACT_pkcs7_sig_note_set_of_authattrs),
+ [ 145] = ASN1_OP_COND_MATCH_JUMP_OR_SKIP, // aaSequence
+ [ 146] = _tagn(CONT, CONS, 2),
+ [ 147] = _jump_target(198),
+ // DigestEncryptionAlgorithmIdentifier
+ [ 148] = ASN1_OP_MATCH,
+ [ 149] = _tag(UNIV, CONS, SEQ),
+ [ 150] = ASN1_OP_MATCH_ACT, // algorithm
+ [ 151] = _tag(UNIV, PRIM, OID),
+ [ 152] = _action(ACT_pkcs7_note_OID),
+ [ 153] = ASN1_OP_MATCH_ANY_OR_SKIP, // parameters
+ [ 154] = ASN1_OP_END_SEQ,
+ [ 155] = ASN1_OP_ACT,
+ [ 156] = _action(ACT_pkcs7_sig_note_pkey_algo),
+ // EncryptedDigest
+ [ 157] = ASN1_OP_MATCH_ACT,
+ [ 158] = _tag(UNIV, PRIM, OTS),
+ [ 159] = _action(ACT_pkcs7_sig_note_signature),
+ [ 160] = ASN1_OP_MATCH_JUMP_OR_SKIP, // uaSet
+ [ 161] = _tagn(CONT, CONS, 1),
+ [ 162] = _jump_target(207),
+ [ 163] = ASN1_OP_COND_MATCH_JUMP_OR_SKIP, // uaSequence
+ [ 164] = _tagn(CONT, CONS, 3),
+ [ 165] = _jump_target(213),
+ [ 166] = ASN1_OP_END_SEQ_ACT,
+ [ 167] = _action(ACT_pkcs7_note_signed_info),
+ [ 168] = ASN1_OP_RETURN,
+
+ // Name
+ [ 169] = ASN1_OP_MATCH,
+ [ 170] = _tag(UNIV, CONS, SEQ),
+ // RelativeDistinguishedName
+ [ 171] = ASN1_OP_MATCH,
+ [ 172] = _tag(UNIV, CONS, SET),
+ // AttributeValueAssertion
+ [ 173] = ASN1_OP_MATCH,
+ [ 174] = _tag(UNIV, CONS, SEQ),
+ [ 175] = ASN1_OP_MATCH_ACT, // attributeType
+ [ 176] = _tag(UNIV, PRIM, OID),
+ [ 177] = _action(ACT_pkcs7_note_OID),
+ [ 178] = ASN1_OP_MATCH_ANY, // attributeValue
+ [ 179] = ASN1_OP_END_SEQ,
+ [ 180] = ASN1_OP_END_SET_OF,
+ [ 181] = _jump_target(173),
+ [ 182] = ASN1_OP_END_SEQ_OF,
+ [ 183] = _jump_target(171),
+ [ 184] = ASN1_OP_ACT,
+ [ 185] = _action(ACT_pkcs7_sig_note_issuer),
+ // CertificateSerialNumber
+ [ 186] = ASN1_OP_MATCH,
+ [ 187] = _tag(UNIV, PRIM, INT),
+ [ 188] = ASN1_OP_ACT,
+ [ 189] = _action(ACT_pkcs7_sig_note_serial),
+ [ 190] = ASN1_OP_END_SEQ,
+ [ 191] = ASN1_OP_RETURN,
+
+ // AuthenticatedAttribute
+ [ 192] = ASN1_OP_MATCH_JUMP,
+ [ 193] = _tag(UNIV, CONS, SEQ),
+ [ 194] = _jump_target(219), // --> AuthenticatedAttribute
+ [ 195] = ASN1_OP_END_SET_OF,
+ [ 196] = _jump_target(192),
+ [ 197] = ASN1_OP_RETURN,
+
+ [ 198] = ASN1_OP_MATCH, // aaSequence
+ [ 199] = _tag(UNIV, CONS, SEQ),
+ // AuthenticatedAttribute
+ [ 200] = ASN1_OP_MATCH_JUMP,
+ [ 201] = _tag(UNIV, CONS, SEQ),
+ [ 202] = _jump_target(219), // --> AuthenticatedAttribute
+ [ 203] = ASN1_OP_END_SEQ_OF,
+ [ 204] = _jump_target(200),
+ [ 205] = ASN1_OP_END_SEQ,
+ [ 206] = ASN1_OP_RETURN,
+
+ // UnauthenticatedAttribute
+ [ 207] = ASN1_OP_MATCH_JUMP,
+ [ 208] = _tag(UNIV, CONS, SEQ),
+ [ 209] = _jump_target(230), // --> UnauthenticatedAttribute
+ [ 210] = ASN1_OP_END_SET_OF,
+ [ 211] = _jump_target(207),
+ [ 212] = ASN1_OP_RETURN,
+
+ // UnauthenticatedAttribute
+ [ 213] = ASN1_OP_MATCH_JUMP,
+ [ 214] = _tag(UNIV, CONS, SEQ),
+ [ 215] = _jump_target(230), // --> UnauthenticatedAttribute
+ [ 216] = ASN1_OP_END_SEQ_OF,
+ [ 217] = _jump_target(213),
+ [ 218] = ASN1_OP_RETURN,
+
+ [ 219] = ASN1_OP_MATCH_ACT, // type
+ [ 220] = _tag(UNIV, PRIM, OID),
+ [ 221] = _action(ACT_pkcs7_note_OID),
+ [ 222] = ASN1_OP_MATCH, // values
+ [ 223] = _tag(UNIV, CONS, SET),
+ [ 224] = ASN1_OP_MATCH_ANY_ACT,
+ [ 225] = _action(ACT_pkcs7_sig_note_authenticated_attr),
+ [ 226] = ASN1_OP_END_SET_OF,
+ [ 227] = _jump_target(224),
+ [ 228] = ASN1_OP_END_SEQ,
+ [ 229] = ASN1_OP_RETURN,
+
+ [ 230] = ASN1_OP_MATCH, // type
+ [ 231] = _tag(UNIV, PRIM, OID),
+ [ 232] = ASN1_OP_MATCH, // values
+ [ 233] = _tag(UNIV, CONS, SET),
+ [ 234] = ASN1_OP_MATCH_ANY,
+ [ 235] = ASN1_OP_END_SET_OF,
+ [ 236] = _jump_target(234),
+ [ 237] = ASN1_OP_END_SEQ,
+ [ 238] = ASN1_OP_RETURN,
+};
+
+const struct asn1_decoder pkcs7_decoder = {
+ .machine = pkcs7_machine,
+ .machlen = sizeof(pkcs7_machine),
+ .actions = pkcs7_action_table,
+};
diff --git a/backport/compat/verification/pkcs7-asn1.h b/backport/compat/verification/pkcs7-asn1.h
new file mode 100644
index 00000000..b34e160f
--- /dev/null
+++ b/backport/compat/verification/pkcs7-asn1.h
@@ -0,0 +1,27 @@
+/*
+ * Automatically generated by asn1_compiler. Do not edit
+ *
+ * ASN.1 parser for pkcs7
+ */
+#include <linux/asn1_decoder.h>
+
+extern const struct asn1_decoder pkcs7_decoder;
+
+extern int pkcs7_check_content_type(void *, size_t, unsigned char, const void *, size_t);
+extern int pkcs7_extract_cert(void *, size_t, unsigned char, const void *, size_t);
+extern int pkcs7_note_OID(void *, size_t, unsigned char, const void *, size_t);
+extern int pkcs7_note_certificate_list(void *, size_t, unsigned char, const void *, size_t);
+extern int pkcs7_note_content(void *, size_t, unsigned char, const void *, size_t);
+extern int pkcs7_note_data(void *, size_t, unsigned char, const void *, size_t);
+extern int pkcs7_note_signed_info(void *, size_t, unsigned char, const void *, size_t);
+extern int pkcs7_note_signeddata_version(void *, size_t, unsigned char, const void *, size_t);
+extern int pkcs7_note_signerinfo_version(void *, size_t, unsigned char, const void *, size_t);
+extern int pkcs7_sig_note_authenticated_attr(void *, size_t, unsigned char, const void *, size_t);
+extern int pkcs7_sig_note_digest_algo(void *, size_t, unsigned char, const void *, size_t);
+extern int pkcs7_sig_note_issuer(void *, size_t, unsigned char, const void *, size_t);
+extern int pkcs7_sig_note_pkey_algo(void *, size_t, unsigned char, const void *, size_t);
+extern int pkcs7_sig_note_serial(void *, size_t, unsigned char, const void *, size_t);
+extern int pkcs7_sig_note_set_of_authattrs(void *, size_t, unsigned char, const void *, size_t);
+extern int pkcs7_sig_note_signature(void *, size_t, unsigned char, const void *, size_t);
+extern int pkcs7_sig_note_skid(void *, size_t, unsigned char, const void *, size_t);
+
diff --git a/backport/compat/verification/public_key.c b/backport/compat/verification/public_key.c
new file mode 100644
index 00000000..10d1672a
--- /dev/null
+++ b/backport/compat/verification/public_key.c
@@ -0,0 +1,131 @@
+/*
+ * Adapted from the kernel for simplicity in backports.
+ *
+ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#define pr_fmt(fmt) "PKEY: "fmt
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/seq_file.h>
+#include <linux/scatterlist.h>
+#include <linux/asn1_decoder.h>
+#include <crypto/public_key.h>
+#include "rsapubkey-asn1.h"
+#include "mbedtls/rsa.h"
+#include "mbedtls/md.h"
+
+void public_key_free(struct public_key *key)
+{
+ if (key) {
+ kfree(key->key);
+ kfree(key);
+ }
+}
+
+int rsa_get_n(void *context, size_t hdrlen, unsigned char tag,
+ const void *value, size_t vlen)
+{
+ mbedtls_rsa_context *rsa = context;
+
+ /* invalid key provided */
+ if (!value || !vlen)
+ return -EINVAL;
+
+ return mbedtls_mpi_read_binary(&rsa->N, value, vlen) ? -EINVAL : 0;
+}
+
+int rsa_get_e(void *context, size_t hdrlen, unsigned char tag,
+ const void *value, size_t vlen)
+{
+ mbedtls_rsa_context *rsa = context;
+
+ /* invalid key provided */
+ if (!value || !vlen)
+ return -EINVAL;
+
+ return mbedtls_mpi_read_binary(&rsa->E, value, vlen) ? -EINVAL : 0;
+}
+
+int public_key_verify_signature(const struct public_key *pkey,
+ const struct public_key_signature *sig)
+{
+ mbedtls_rsa_context rsa;
+ mbedtls_md_type_t md_alg;
+ const u8 *sigdata = sig->s;
+ int s_size = sig->s_size;
+ int ret;
+
+ if (WARN_ON(!pkey))
+ return -EINVAL;
+
+ if (strcmp(sig->pkey_algo, "rsa"))
+ return -ENOTSUPP;
+
+ if (strcmp(sig->hash_algo, "sha1") == 0)
+ md_alg = MBEDTLS_MD_SHA1;
+ else if (strcmp(sig->hash_algo, "sha256") == 0)
+ md_alg = MBEDTLS_MD_SHA256;
+ else
+ return -ENOTSUPP;
+
+ mbedtls_rsa_init(&rsa, MBEDTLS_RSA_PKCS_V15, 0);
+
+ ret = asn1_ber_decoder(&rsapubkey_decoder, &rsa,
+ pkey->key, pkey->keylen);
+ if (ret)
+ goto free;
+
+ rsa.len = (mbedtls_mpi_bitlen(&rsa.N) + 7) >> 3;
+
+ /*
+ * In some cases (from X.509 certificates) we get here with a
+ * BIT_STRING ASN.1 object, in which the first byte indicates
+ * the number of unused bits in the bit string (in case the
+ * string isn't a multiple of 8 long).
+ * Assume here that it's always a multiple of 8, and just skip
+ * the additional byte.
+ */
+ if (s_size == rsa.len + 1 && sigdata[0] == 0) {
+ sigdata = sig->s + 1;
+ s_size -= 1;
+ }
+
+ if (rsa.len != s_size) {
+ ret = -EINVAL;
+ goto free;
+ }
+
+ ret = mbedtls_rsa_pkcs1_verify(&rsa, NULL, NULL, MBEDTLS_RSA_PUBLIC,
+ md_alg, 0, sig->digest, sigdata);
+
+ if (ret)
+ ret = -EKEYREJECTED;
+ else
+ ret = 0;
+
+ free:
+ mbedtls_rsa_free(&rsa);
+
+ return ret;
+}
+
+void public_key_signature_free(struct public_key_signature *sig)
+{
+ int i;
+
+ if (sig) {
+ for (i = 0; i < ARRAY_SIZE(sig->auth_ids); i++)
+ kfree(sig->auth_ids[i]);
+ kfree(sig->s);
+ kfree(sig->digest);
+ kfree(sig);
+ }
+}
diff --git a/backport/compat/verification/rsa.c b/backport/compat/verification/rsa.c
new file mode 100644
index 00000000..605bd885
--- /dev/null
+++ b/backport/compat/verification/rsa.c
@@ -0,0 +1,1872 @@
+/*
+ * The RSA public-key cryptosystem
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: GPL-2.0
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * This file is part of mbed TLS (https://tls.mbed.org)
+ */
+/*
+ * The following sources were referenced in the design of this implementation
+ * of the RSA algorithm:
+ *
+ * [1] A method for obtaining digital signatures and public-key cryptosystems
+ * R Rivest, A Shamir, and L Adleman
+ * http://people.csail.mit.edu/rivest/pubs.html#RSA78
+ *
+ * [2] Handbook of Applied Cryptography - 1997, Chapter 8
+ * Menezes, van Oorschot and Vanstone
+ *
+ * [3] Malware Guard Extension: Using SGX to Conceal Cache Attacks
+ * Michael Schwarz, Samuel Weiser, Daniel Gruss, Clémentine Maurice and
+ * Stefan Mangard
+ * https://arxiv.org/abs/1702.08719v2
+ *
+ */
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "mbedtls/config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#if defined(MBEDTLS_RSA_C)
+
+#include "mbedtls/rsa.h"
+#include "mbedtls/oid.h"
+
+#if defined(MBEDTLS_PKCS1_V21)
+#include "mbedtls/md.h"
+#endif
+
+#if defined(MBEDTLS_PKCS1_V15) && !defined(__OpenBSD__)
+#include <stdlib.h>
+#endif
+
+#if defined(MBEDTLS_PLATFORM_C)
+#include "mbedtls/platform.h"
+#else
+#include <stdio.h>
+#define mbedtls_printf printf
+#define mbedtls_calloc calloc
+#define mbedtls_free free
+#endif
+
+/* Implementation that should never be optimized out by the compiler */
+static void mbedtls_zeroize( void *v, size_t n ) {
+ volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0;
+}
+
+/*
+ * Initialize an RSA context
+ */
+void mbedtls_rsa_init( mbedtls_rsa_context *ctx,
+ int padding,
+ int hash_id )
+{
+ memset( ctx, 0, sizeof( mbedtls_rsa_context ) );
+
+ mbedtls_rsa_set_padding( ctx, padding, hash_id );
+
+#if defined(MBEDTLS_THREADING_C)
+ mbedtls_mutex_init( &ctx->mutex );
+#endif
+}
+
+/*
+ * Set padding for an existing RSA context
+ */
+void mbedtls_rsa_set_padding( mbedtls_rsa_context *ctx, int padding, int hash_id )
+{
+ ctx->padding = padding;
+ ctx->hash_id = hash_id;
+}
+
+#if defined(MBEDTLS_GENPRIME)
+
+/*
+ * Generate an RSA keypair
+ */
+int mbedtls_rsa_gen_key( mbedtls_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ unsigned int nbits, int exponent )
+{
+ int ret;
+ mbedtls_mpi P1, Q1, H, G;
+
+ if( f_rng == NULL || nbits < 128 || exponent < 3 )
+ return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+
+ if( nbits % 2 )
+ return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+
+ mbedtls_mpi_init( &P1 ); mbedtls_mpi_init( &Q1 );
+ mbedtls_mpi_init( &H ); mbedtls_mpi_init( &G );
+
+ /*
+ * find primes P and Q with Q < P so that:
+ * GCD( E, (P-1)*(Q-1) ) == 1
+ */
+ MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &ctx->E, exponent ) );
+
+ do
+ {
+ MBEDTLS_MPI_CHK( mbedtls_mpi_gen_prime( &ctx->P, nbits >> 1, 0,
+ f_rng, p_rng ) );
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_gen_prime( &ctx->Q, nbits >> 1, 0,
+ f_rng, p_rng ) );
+
+ if( mbedtls_mpi_cmp_mpi( &ctx->P, &ctx->Q ) == 0 )
+ continue;
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->N, &ctx->P, &ctx->Q ) );
+ if( mbedtls_mpi_bitlen( &ctx->N ) != nbits )
+ continue;
+
+ if( mbedtls_mpi_cmp_mpi( &ctx->P, &ctx->Q ) < 0 )
+ mbedtls_mpi_swap( &ctx->P, &ctx->Q );
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &P1, &ctx->P, 1 ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &Q1, &ctx->Q, 1 ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &H, &P1, &Q1 ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &G, &ctx->E, &H ) );
+ }
+ while( mbedtls_mpi_cmp_int( &G, 1 ) != 0 );
+
+ /*
+ * D = E^-1 mod ((P-1)*(Q-1))
+ * DP = D mod (P - 1)
+ * DQ = D mod (Q - 1)
+ * QP = Q^-1 mod P
+ */
+ MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &ctx->D , &ctx->E, &H ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->DP, &ctx->D, &P1 ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->DQ, &ctx->D, &Q1 ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &ctx->QP, &ctx->Q, &ctx->P ) );
+
+ ctx->len = ( mbedtls_mpi_bitlen( &ctx->N ) + 7 ) >> 3;
+
+cleanup:
+
+ mbedtls_mpi_free( &P1 ); mbedtls_mpi_free( &Q1 ); mbedtls_mpi_free( &H ); mbedtls_mpi_free( &G );
+
+ if( ret != 0 )
+ {
+ mbedtls_rsa_free( ctx );
+ return( MBEDTLS_ERR_RSA_KEY_GEN_FAILED + ret );
+ }
+
+ return( 0 );
+}
+
+#endif /* MBEDTLS_GENPRIME */
+
+/*
+ * Check a public RSA key
+ */
+int mbedtls_rsa_check_pubkey( const mbedtls_rsa_context *ctx )
+{
+ if( !ctx->N.p || !ctx->E.p )
+ return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED );
+
+ if( ( ctx->N.p[0] & 1 ) == 0 ||
+ ( ctx->E.p[0] & 1 ) == 0 )
+ return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED );
+
+ if( mbedtls_mpi_bitlen( &ctx->N ) < 128 ||
+ mbedtls_mpi_bitlen( &ctx->N ) > MBEDTLS_MPI_MAX_BITS )
+ return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED );
+
+ if( mbedtls_mpi_bitlen( &ctx->E ) < 2 ||
+ mbedtls_mpi_cmp_mpi( &ctx->E, &ctx->N ) >= 0 )
+ return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED );
+
+ return( 0 );
+}
+
+/*
+ * Check a private RSA key
+ */
+int mbedtls_rsa_check_privkey( const mbedtls_rsa_context *ctx )
+{
+ int ret;
+ mbedtls_mpi PQ, DE, P1, Q1, H, I, G, G2, L1, L2, DP, DQ, QP;
+
+ if( ( ret = mbedtls_rsa_check_pubkey( ctx ) ) != 0 )
+ return( ret );
+
+ if( !ctx->P.p || !ctx->Q.p || !ctx->D.p )
+ return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED );
+
+ mbedtls_mpi_init( &PQ ); mbedtls_mpi_init( &DE ); mbedtls_mpi_init( &P1 ); mbedtls_mpi_init( &Q1 );
+ mbedtls_mpi_init( &H ); mbedtls_mpi_init( &I ); mbedtls_mpi_init( &G ); mbedtls_mpi_init( &G2 );
+ mbedtls_mpi_init( &L1 ); mbedtls_mpi_init( &L2 ); mbedtls_mpi_init( &DP ); mbedtls_mpi_init( &DQ );
+ mbedtls_mpi_init( &QP );
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &PQ, &ctx->P, &ctx->Q ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &DE, &ctx->D, &ctx->E ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &P1, &ctx->P, 1 ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &Q1, &ctx->Q, 1 ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &H, &P1, &Q1 ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &G, &ctx->E, &H ) );
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &G2, &P1, &Q1 ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( &L1, &L2, &H, &G2 ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &I, &DE, &L1 ) );
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &DP, &ctx->D, &P1 ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &DQ, &ctx->D, &Q1 ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &QP, &ctx->Q, &ctx->P ) );
+ /*
+ * Check for a valid PKCS1v2 private key
+ */
+ if( mbedtls_mpi_cmp_mpi( &PQ, &ctx->N ) != 0 ||
+ mbedtls_mpi_cmp_mpi( &DP, &ctx->DP ) != 0 ||
+ mbedtls_mpi_cmp_mpi( &DQ, &ctx->DQ ) != 0 ||
+ mbedtls_mpi_cmp_mpi( &QP, &ctx->QP ) != 0 ||
+ mbedtls_mpi_cmp_int( &L2, 0 ) != 0 ||
+ mbedtls_mpi_cmp_int( &I, 1 ) != 0 ||
+ mbedtls_mpi_cmp_int( &G, 1 ) != 0 )
+ {
+ ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED;
+ }
+
+cleanup:
+ mbedtls_mpi_free( &PQ ); mbedtls_mpi_free( &DE ); mbedtls_mpi_free( &P1 ); mbedtls_mpi_free( &Q1 );
+ mbedtls_mpi_free( &H ); mbedtls_mpi_free( &I ); mbedtls_mpi_free( &G ); mbedtls_mpi_free( &G2 );
+ mbedtls_mpi_free( &L1 ); mbedtls_mpi_free( &L2 ); mbedtls_mpi_free( &DP ); mbedtls_mpi_free( &DQ );
+ mbedtls_mpi_free( &QP );
+
+ if( ret == MBEDTLS_ERR_RSA_KEY_CHECK_FAILED )
+ return( ret );
+
+ if( ret != 0 )
+ return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED + ret );
+
+ return( 0 );
+}
+
+/*
+ * Check if contexts holding a public and private key match
+ */
+int mbedtls_rsa_check_pub_priv( const mbedtls_rsa_context *pub, const mbedtls_rsa_context *prv )
+{
+ if( mbedtls_rsa_check_pubkey( pub ) != 0 ||
+ mbedtls_rsa_check_privkey( prv ) != 0 )
+ {
+ return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED );
+ }
+
+ if( mbedtls_mpi_cmp_mpi( &pub->N, &prv->N ) != 0 ||
+ mbedtls_mpi_cmp_mpi( &pub->E, &prv->E ) != 0 )
+ {
+ return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED );
+ }
+
+ return( 0 );
+}
+
+/*
+ * Do an RSA public key operation
+ */
+int mbedtls_rsa_public( mbedtls_rsa_context *ctx,
+ const unsigned char *input,
+ unsigned char *output )
+{
+ int ret;
+ size_t olen;
+ mbedtls_mpi T;
+
+ mbedtls_mpi_init( &T );
+
+#if defined(MBEDTLS_THREADING_C)
+ if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 )
+ return( ret );
+#endif
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &T, input, ctx->len ) );
+
+ if( mbedtls_mpi_cmp_mpi( &T, &ctx->N ) >= 0 )
+ {
+ ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
+ goto cleanup;
+ }
+
+ olen = ctx->len;
+ MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &T, &T, &ctx->E, &ctx->N, &ctx->RN ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &T, output, olen ) );
+
+cleanup:
+#if defined(MBEDTLS_THREADING_C)
+ if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 )
+ return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
+#endif
+
+ mbedtls_mpi_free( &T );
+
+ if( ret != 0 )
+ return( MBEDTLS_ERR_RSA_PUBLIC_FAILED + ret );
+
+ return( 0 );
+}
+
+/*
+ * Generate or update blinding values, see section 10 of:
+ * KOCHER, Paul C. Timing attacks on implementations of Diffie-Hellman, RSA,
+ * DSS, and other systems. In : Advances in Cryptology-CRYPTO'96. Springer
+ * Berlin Heidelberg, 1996. p. 104-113.
+ */
+static int rsa_prepare_blinding( mbedtls_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
+{
+ int ret, count = 0;
+
+ if( ctx->Vf.p != NULL )
+ {
+ /* We already have blinding values, just update them by squaring */
+ MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vi, &ctx->Vi, &ctx->Vi ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vi, &ctx->Vi, &ctx->N ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vf, &ctx->Vf, &ctx->Vf ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vf, &ctx->Vf, &ctx->N ) );
+
+ goto cleanup;
+ }
+
+ /* Unblinding value: Vf = random number, invertible mod N */
+ do {
+ if( count++ > 10 )
+ return( MBEDTLS_ERR_RSA_RNG_FAILED );
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &ctx->Vf, ctx->len - 1, f_rng, p_rng ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &ctx->Vi, &ctx->Vf, &ctx->N ) );
+ } while( mbedtls_mpi_cmp_int( &ctx->Vi, 1 ) != 0 );
+
+ /* Blinding value: Vi = Vf^(-e) mod N */
+ MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &ctx->Vi, &ctx->Vf, &ctx->N ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->Vi, &ctx->Vi, &ctx->E, &ctx->N, &ctx->RN ) );
+
+
+cleanup:
+ return( ret );
+}
+
+/*
+ * Exponent blinding supposed to prevent side-channel attacks using multiple
+ * traces of measurements to recover the RSA key. The more collisions are there,
+ * the more bits of the key can be recovered. See [3].
+ *
+ * Collecting n collisions with m bit long blinding value requires 2^(m-m/n)
+ * observations on avarage.
+ *
+ * For example with 28 byte blinding to achieve 2 collisions the adversary has
+ * to make 2^112 observations on avarage.
+ *
+ * (With the currently (as of 2017 April) known best algorithms breaking 2048
+ * bit RSA requires approximately as much time as trying out 2^112 random keys.
+ * Thus in this sense with 28 byte blinding the security is not reduced by
+ * side-channel attacks like the one in [3])
+ *
+ * This countermeasure does not help if the key recovery is possible with a
+ * single trace.
+ */
+#define RSA_EXPONENT_BLINDING 28
+
+/*
+ * Do an RSA private key operation
+ */
+int mbedtls_rsa_private( mbedtls_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ const unsigned char *input,
+ unsigned char *output )
+{
+ int ret;
+ size_t olen;
+ mbedtls_mpi T, T1, T2;
+ mbedtls_mpi P1, Q1, R;
+#if defined(MBEDTLS_RSA_NO_CRT)
+ mbedtls_mpi D_blind;
+ mbedtls_mpi *D = &ctx->D;
+#else
+ mbedtls_mpi DP_blind, DQ_blind;
+ mbedtls_mpi *DP = &ctx->DP;
+ mbedtls_mpi *DQ = &ctx->DQ;
+#endif
+
+ /* Make sure we have private key info, prevent possible misuse */
+ if( ctx->P.p == NULL || ctx->Q.p == NULL || ctx->D.p == NULL )
+ return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+
+ mbedtls_mpi_init( &T ); mbedtls_mpi_init( &T1 ); mbedtls_mpi_init( &T2 );
+ mbedtls_mpi_init( &P1 ); mbedtls_mpi_init( &Q1 ); mbedtls_mpi_init( &R );
+
+
+ if( f_rng != NULL )
+ {
+#if defined(MBEDTLS_RSA_NO_CRT)
+ mbedtls_mpi_init( &D_blind );
+#else
+ mbedtls_mpi_init( &DP_blind );
+ mbedtls_mpi_init( &DQ_blind );
+#endif
+ }
+
+
+#if defined(MBEDTLS_THREADING_C)
+ if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 )
+ return( ret );
+#endif
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &T, input, ctx->len ) );
+ if( mbedtls_mpi_cmp_mpi( &T, &ctx->N ) >= 0 )
+ {
+ ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
+ goto cleanup;
+ }
+
+ if( f_rng != NULL )
+ {
+ /*
+ * Blinding
+ * T = T * Vi mod N
+ */
+ MBEDTLS_MPI_CHK( rsa_prepare_blinding( ctx, f_rng, p_rng ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, &T, &ctx->Vi ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &T, &T, &ctx->N ) );
+
+ /*
+ * Exponent blinding
+ */
+ MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &P1, &ctx->P, 1 ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &Q1, &ctx->Q, 1 ) );
+
+#if defined(MBEDTLS_RSA_NO_CRT)
+ /*
+ * D_blind = ( P - 1 ) * ( Q - 1 ) * R + D
+ */
+ MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &R, RSA_EXPONENT_BLINDING,
+ f_rng, p_rng ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &D_blind, &P1, &Q1 ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &D_blind, &D_blind, &R ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &D_blind, &D_blind, &ctx->D ) );
+
+ D = &D_blind;
+#else
+ /*
+ * DP_blind = ( P - 1 ) * R + DP
+ */
+ MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &R, RSA_EXPONENT_BLINDING,
+ f_rng, p_rng ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &DP_blind, &P1, &R ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &DP_blind, &DP_blind,
+ &ctx->DP ) );
+
+ DP = &DP_blind;
+
+ /*
+ * DQ_blind = ( Q - 1 ) * R + DQ
+ */
+ MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &R, RSA_EXPONENT_BLINDING,
+ f_rng, p_rng ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &DQ_blind, &Q1, &R ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &DQ_blind, &DQ_blind,
+ &ctx->DQ ) );
+
+ DQ = &DQ_blind;
+#endif /* MBEDTLS_RSA_NO_CRT */
+ }
+
+#if defined(MBEDTLS_RSA_NO_CRT)
+ MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &T, &T, D, &ctx->N, &ctx->RN ) );
+#else
+ /*
+ * Faster decryption using the CRT
+ *
+ * T1 = input ^ dP mod P
+ * T2 = input ^ dQ mod Q
+ */
+ MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &T1, &T, DP, &ctx->P, &ctx->RP ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &T2, &T, DQ, &ctx->Q, &ctx->RQ ) );
+
+ /*
+ * T = (T1 - T2) * (Q^-1 mod P) mod P
+ */
+ MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &T, &T1, &T2 ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T1, &T, &ctx->QP ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &T, &T1, &ctx->P ) );
+
+ /*
+ * T = T2 + T * Q
+ */
+ MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T1, &T, &ctx->Q ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &T, &T2, &T1 ) );
+#endif /* MBEDTLS_RSA_NO_CRT */
+
+ if( f_rng != NULL )
+ {
+ /*
+ * Unblind
+ * T = T * Vf mod N
+ */
+ MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, &T, &ctx->Vf ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &T, &T, &ctx->N ) );
+ }
+
+ olen = ctx->len;
+ MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &T, output, olen ) );
+
+cleanup:
+#if defined(MBEDTLS_THREADING_C)
+ if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 )
+ return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
+#endif
+
+ mbedtls_mpi_free( &T ); mbedtls_mpi_free( &T1 ); mbedtls_mpi_free( &T2 );
+ mbedtls_mpi_free( &P1 ); mbedtls_mpi_free( &Q1 ); mbedtls_mpi_free( &R );
+
+ if( f_rng != NULL )
+ {
+#if defined(MBEDTLS_RSA_NO_CRT)
+ mbedtls_mpi_free( &D_blind );
+#else
+ mbedtls_mpi_free( &DP_blind );
+ mbedtls_mpi_free( &DQ_blind );
+#endif
+ }
+
+ if( ret != 0 )
+ return( MBEDTLS_ERR_RSA_PRIVATE_FAILED + ret );
+
+ return( 0 );
+}
+
+#if defined(MBEDTLS_PKCS1_V21)
+/**
+ * Generate and apply the MGF1 operation (from PKCS#1 v2.1) to a buffer.
+ *
+ * \param dst buffer to mask
+ * \param dlen length of destination buffer
+ * \param src source of the mask generation
+ * \param slen length of the source buffer
+ * \param md_ctx message digest context to use
+ */
+static void mgf_mask( unsigned char *dst, size_t dlen, unsigned char *src,
+ size_t slen, mbedtls_md_context_t *md_ctx )
+{
+ unsigned char mask[MBEDTLS_MD_MAX_SIZE];
+ unsigned char counter[4];
+ unsigned char *p;
+ unsigned int hlen;
+ size_t i, use_len;
+
+ memset( mask, 0, MBEDTLS_MD_MAX_SIZE );
+ memset( counter, 0, 4 );
+
+ hlen = mbedtls_md_get_size( md_ctx->md_info );
+
+ /* Generate and apply dbMask */
+ p = dst;
+
+ while( dlen > 0 )
+ {
+ use_len = hlen;
+ if( dlen < hlen )
+ use_len = dlen;
+
+ mbedtls_md_starts( md_ctx );
+ mbedtls_md_update( md_ctx, src, slen );
+ mbedtls_md_update( md_ctx, counter, 4 );
+ mbedtls_md_finish( md_ctx, mask );
+
+ for( i = 0; i < use_len; ++i )
+ *p++ ^= mask[i];
+
+ counter[3]++;
+
+ dlen -= use_len;
+ }
+
+ mbedtls_zeroize( mask, sizeof( mask ) );
+}
+#endif /* MBEDTLS_PKCS1_V21 */
+
+#if defined(MBEDTLS_PKCS1_V21)
+/*
+ * Implementation of the PKCS#1 v2.1 RSAES-OAEP-ENCRYPT function
+ */
+int mbedtls_rsa_rsaes_oaep_encrypt( mbedtls_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ int mode,
+ const unsigned char *label, size_t label_len,
+ size_t ilen,
+ const unsigned char *input,
+ unsigned char *output )
+{
+ size_t olen;
+ int ret;
+ unsigned char *p = output;
+ unsigned int hlen;
+ const mbedtls_md_info_t *md_info;
+ mbedtls_md_context_t md_ctx;
+
+ if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V21 )
+ return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+
+ if( f_rng == NULL )
+ return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+
+ md_info = mbedtls_md_info_from_type( (mbedtls_md_type_t) ctx->hash_id );
+ if( md_info == NULL )
+ return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+
+ olen = ctx->len;
+ hlen = mbedtls_md_get_size( md_info );
+
+ /* first comparison checks for overflow */
+ if( ilen + 2 * hlen + 2 < ilen || olen < ilen + 2 * hlen + 2 )
+ return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+
+ memset( output, 0, olen );
+
+ *p++ = 0;
+
+ /* Generate a random octet string seed */
+ if( ( ret = f_rng( p_rng, p, hlen ) ) != 0 )
+ return( MBEDTLS_ERR_RSA_RNG_FAILED + ret );
+
+ p += hlen;
+
+ /* Construct DB */
+ mbedtls_md( md_info, label, label_len, p );
+ p += hlen;
+ p += olen - 2 * hlen - 2 - ilen;
+ *p++ = 1;
+ memcpy( p, input, ilen );
+
+ mbedtls_md_init( &md_ctx );
+ if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 0 ) ) != 0 )
+ {
+ mbedtls_md_free( &md_ctx );
+ return( ret );
+ }
+
+ /* maskedDB: Apply dbMask to DB */
+ mgf_mask( output + hlen + 1, olen - hlen - 1, output + 1, hlen,
+ &md_ctx );
+
+ /* maskedSeed: Apply seedMask to seed */
+ mgf_mask( output + 1, hlen, output + hlen + 1, olen - hlen - 1,
+ &md_ctx );
+
+ mbedtls_md_free( &md_ctx );
+
+ return( ( mode == MBEDTLS_RSA_PUBLIC )
+ ? mbedtls_rsa_public( ctx, output, output )
+ : mbedtls_rsa_private( ctx, f_rng, p_rng, output, output ) );
+}
+#endif /* MBEDTLS_PKCS1_V21 */
+
+#if defined(MBEDTLS_PKCS1_V15)
+/*
+ * Implementation of the PKCS#1 v2.1 RSAES-PKCS1-V1_5-ENCRYPT function
+ */
+int mbedtls_rsa_rsaes_pkcs1_v15_encrypt( mbedtls_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ int mode, size_t ilen,
+ const unsigned char *input,
+ unsigned char *output )
+{
+ size_t nb_pad, olen;
+ int ret;
+ unsigned char *p = output;
+
+ if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 )
+ return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+
+ // We don't check p_rng because it won't be dereferenced here
+ if( f_rng == NULL || input == NULL || output == NULL )
+ return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+
+ olen = ctx->len;
+
+ /* first comparison checks for overflow */
+ if( ilen + 11 < ilen || olen < ilen + 11 )
+ return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+
+ nb_pad = olen - 3 - ilen;
+
+ *p++ = 0;
+ if( mode == MBEDTLS_RSA_PUBLIC )
+ {
+ *p++ = MBEDTLS_RSA_CRYPT;
+
+ while( nb_pad-- > 0 )
+ {
+ int rng_dl = 100;
+
+ do {
+ ret = f_rng( p_rng, p, 1 );
+ } while( *p == 0 && --rng_dl && ret == 0 );
+
+ /* Check if RNG failed to generate data */
+ if( rng_dl == 0 || ret != 0 )
+ return( MBEDTLS_ERR_RSA_RNG_FAILED + ret );
+
+ p++;
+ }
+ }
+ else
+ {
+ *p++ = MBEDTLS_RSA_SIGN;
+
+ while( nb_pad-- > 0 )
+ *p++ = 0xFF;
+ }
+
+ *p++ = 0;
+ memcpy( p, input, ilen );
+
+ return( ( mode == MBEDTLS_RSA_PUBLIC )
+ ? mbedtls_rsa_public( ctx, output, output )
+ : mbedtls_rsa_private( ctx, f_rng, p_rng, output, output ) );
+}
+#endif /* MBEDTLS_PKCS1_V15 */
+
+/*
+ * Add the message padding, then do an RSA operation
+ */
+int mbedtls_rsa_pkcs1_encrypt( mbedtls_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ int mode, size_t ilen,
+ const unsigned char *input,
+ unsigned char *output )
+{
+ switch( ctx->padding )
+ {
+#if defined(MBEDTLS_PKCS1_V15)
+ case MBEDTLS_RSA_PKCS_V15:
+ return mbedtls_rsa_rsaes_pkcs1_v15_encrypt( ctx, f_rng, p_rng, mode, ilen,
+ input, output );
+#endif
+
+#if defined(MBEDTLS_PKCS1_V21)
+ case MBEDTLS_RSA_PKCS_V21:
+ return mbedtls_rsa_rsaes_oaep_encrypt( ctx, f_rng, p_rng, mode, NULL, 0,
+ ilen, input, output );
+#endif
+
+ default:
+ return( MBEDTLS_ERR_RSA_INVALID_PADDING );
+ }
+}
+
+#if defined(MBEDTLS_PKCS1_V21)
+/*
+ * Implementation of the PKCS#1 v2.1 RSAES-OAEP-DECRYPT function
+ */
+int mbedtls_rsa_rsaes_oaep_decrypt( mbedtls_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ int mode,
+ const unsigned char *label, size_t label_len,
+ size_t *olen,
+ const unsigned char *input,
+ unsigned char *output,
+ size_t output_max_len )
+{
+ int ret;
+ size_t ilen, i, pad_len;
+ unsigned char *p, bad, pad_done;
+ unsigned char buf[MBEDTLS_MPI_MAX_SIZE];
+ unsigned char lhash[MBEDTLS_MD_MAX_SIZE];
+ unsigned int hlen;
+ const mbedtls_md_info_t *md_info;
+ mbedtls_md_context_t md_ctx;
+
+ /*
+ * Parameters sanity checks
+ */
+ if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V21 )
+ return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+
+ ilen = ctx->len;
+
+ if( ilen < 16 || ilen > sizeof( buf ) )
+ return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+
+ md_info = mbedtls_md_info_from_type( (mbedtls_md_type_t) ctx->hash_id );
+ if( md_info == NULL )
+ return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+
+ hlen = mbedtls_md_get_size( md_info );
+
+ // checking for integer underflow
+ if( 2 * hlen + 2 > ilen )
+ return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+
+ /*
+ * RSA operation
+ */
+ ret = ( mode == MBEDTLS_RSA_PUBLIC )
+ ? mbedtls_rsa_public( ctx, input, buf )
+ : mbedtls_rsa_private( ctx, f_rng, p_rng, input, buf );
+
+ if( ret != 0 )
+ goto cleanup;
+
+ /*
+ * Unmask data and generate lHash
+ */
+ mbedtls_md_init( &md_ctx );
+ if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 0 ) ) != 0 )
+ {
+ mbedtls_md_free( &md_ctx );
+ goto cleanup;
+ }
+
+
+ /* Generate lHash */
+ mbedtls_md( md_info, label, label_len, lhash );
+
+ /* seed: Apply seedMask to maskedSeed */
+ mgf_mask( buf + 1, hlen, buf + hlen + 1, ilen - hlen - 1,
+ &md_ctx );
+
+ /* DB: Apply dbMask to maskedDB */
+ mgf_mask( buf + hlen + 1, ilen - hlen - 1, buf + 1, hlen,
+ &md_ctx );
+
+ mbedtls_md_free( &md_ctx );
+
+ /*
+ * Check contents, in "constant-time"
+ */
+ p = buf;
+ bad = 0;
+
+ bad |= *p++; /* First byte must be 0 */
+
+ p += hlen; /* Skip seed */
+
+ /* Check lHash */
+ for( i = 0; i < hlen; i++ )
+ bad |= lhash[i] ^ *p++;
+
+ /* Get zero-padding len, but always read till end of buffer
+ * (minus one, for the 01 byte) */
+ pad_len = 0;
+ pad_done = 0;
+ for( i = 0; i < ilen - 2 * hlen - 2; i++ )
+ {
+ pad_done |= p[i];
+ pad_len += ((pad_done | (unsigned char)-pad_done) >> 7) ^ 1;
+ }
+
+ p += pad_len;
+ bad |= *p++ ^ 0x01;
+
+ /*
+ * The only information "leaked" is whether the padding was correct or not
+ * (eg, no data is copied if it was not correct). This meets the
+ * recommendations in PKCS#1 v2.2: an opponent cannot distinguish between
+ * the different error conditions.
+ */
+ if( bad != 0 )
+ {
+ ret = MBEDTLS_ERR_RSA_INVALID_PADDING;
+ goto cleanup;
+ }
+
+ if( ilen - ( p - buf ) > output_max_len )
+ {
+ ret = MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE;
+ goto cleanup;
+ }
+
+ *olen = ilen - (p - buf);
+ memcpy( output, p, *olen );
+ ret = 0;
+
+cleanup:
+ mbedtls_zeroize( buf, sizeof( buf ) );
+ mbedtls_zeroize( lhash, sizeof( lhash ) );
+
+ return( ret );
+}
+#endif /* MBEDTLS_PKCS1_V21 */
+
+#if defined(MBEDTLS_PKCS1_V15)
+/*
+ * Implementation of the PKCS#1 v2.1 RSAES-PKCS1-V1_5-DECRYPT function
+ */
+int mbedtls_rsa_rsaes_pkcs1_v15_decrypt( mbedtls_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ int mode, size_t *olen,
+ const unsigned char *input,
+ unsigned char *output,
+ size_t output_max_len)
+{
+ int ret;
+ size_t ilen, pad_count = 0, i;
+ unsigned char *p, bad, pad_done = 0;
+ unsigned char buf[MBEDTLS_MPI_MAX_SIZE];
+
+ if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 )
+ return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+
+ ilen = ctx->len;
+
+ if( ilen < 16 || ilen > sizeof( buf ) )
+ return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+
+ ret = ( mode == MBEDTLS_RSA_PUBLIC )
+ ? mbedtls_rsa_public( ctx, input, buf )
+ : mbedtls_rsa_private( ctx, f_rng, p_rng, input, buf );
+
+ if( ret != 0 )
+ goto cleanup;
+
+ p = buf;
+ bad = 0;
+
+ /*
+ * Check and get padding len in "constant-time"
+ */
+ bad |= *p++; /* First byte must be 0 */
+
+ /* This test does not depend on secret data */
+ if( mode == MBEDTLS_RSA_PRIVATE )
+ {
+ bad |= *p++ ^ MBEDTLS_RSA_CRYPT;
+
+ /* Get padding len, but always read till end of buffer
+ * (minus one, for the 00 byte) */
+ for( i = 0; i < ilen - 3; i++ )
+ {
+ pad_done |= ((p[i] | (unsigned char)-p[i]) >> 7) ^ 1;
+ pad_count += ((pad_done | (unsigned char)-pad_done) >> 7) ^ 1;
+ }
+
+ p += pad_count;
+ bad |= *p++; /* Must be zero */
+ }
+ else
+ {
+ bad |= *p++ ^ MBEDTLS_RSA_SIGN;
+
+ /* Get padding len, but always read till end of buffer
+ * (minus one, for the 00 byte) */
+ for( i = 0; i < ilen - 3; i++ )
+ {
+ pad_done |= ( p[i] != 0xFF );
+ pad_count += ( pad_done == 0 );
+ }
+
+ p += pad_count;
+ bad |= *p++; /* Must be zero */
+ }
+
+ bad |= ( pad_count < 8 );
+
+ if( bad )
+ {
+ ret = MBEDTLS_ERR_RSA_INVALID_PADDING;
+ goto cleanup;
+ }
+
+ if( ilen - ( p - buf ) > output_max_len )
+ {
+ ret = MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE;
+ goto cleanup;
+ }
+
+ *olen = ilen - (p - buf);
+ memcpy( output, p, *olen );
+ ret = 0;
+
+cleanup:
+ mbedtls_zeroize( buf, sizeof( buf ) );
+
+ return( ret );
+}
+#endif /* MBEDTLS_PKCS1_V15 */
+
+/*
+ * Do an RSA operation, then remove the message padding
+ */
+int mbedtls_rsa_pkcs1_decrypt( mbedtls_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ int mode, size_t *olen,
+ const unsigned char *input,
+ unsigned char *output,
+ size_t output_max_len)
+{
+ switch( ctx->padding )
+ {
+#if defined(MBEDTLS_PKCS1_V15)
+ case MBEDTLS_RSA_PKCS_V15:
+ return mbedtls_rsa_rsaes_pkcs1_v15_decrypt( ctx, f_rng, p_rng, mode, olen,
+ input, output, output_max_len );
+#endif
+
+#if defined(MBEDTLS_PKCS1_V21)
+ case MBEDTLS_RSA_PKCS_V21:
+ return mbedtls_rsa_rsaes_oaep_decrypt( ctx, f_rng, p_rng, mode, NULL, 0,
+ olen, input, output,
+ output_max_len );
+#endif
+
+ default:
+ return( MBEDTLS_ERR_RSA_INVALID_PADDING );
+ }
+}
+
+#if defined(MBEDTLS_PKCS1_V21)
+/*
+ * Implementation of the PKCS#1 v2.1 RSASSA-PSS-SIGN function
+ */
+int mbedtls_rsa_rsassa_pss_sign( mbedtls_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ int mode,
+ mbedtls_md_type_t md_alg,
+ unsigned int hashlen,
+ const unsigned char *hash,
+ unsigned char *sig )
+{
+ size_t olen;
+ unsigned char *p = sig;
+ unsigned char salt[MBEDTLS_MD_MAX_SIZE];
+ unsigned int slen, hlen, offset = 0;
+ int ret;
+ size_t msb;
+ const mbedtls_md_info_t *md_info;
+ mbedtls_md_context_t md_ctx;
+
+ if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V21 )
+ return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+
+ if( f_rng == NULL )
+ return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+
+ olen = ctx->len;
+
+ if( md_alg != MBEDTLS_MD_NONE )
+ {
+ /* Gather length of hash to sign */
+ md_info = mbedtls_md_info_from_type( md_alg );
+ if( md_info == NULL )
+ return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+
+ hashlen = mbedtls_md_get_size( md_info );
+ }
+
+ md_info = mbedtls_md_info_from_type( (mbedtls_md_type_t) ctx->hash_id );
+ if( md_info == NULL )
+ return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+
+ hlen = mbedtls_md_get_size( md_info );
+ slen = hlen;
+
+ if( olen < hlen + slen + 2 )
+ return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+
+ memset( sig, 0, olen );
+
+ /* Generate salt of length slen */
+ if( ( ret = f_rng( p_rng, salt, slen ) ) != 0 )
+ return( MBEDTLS_ERR_RSA_RNG_FAILED + ret );
+
+ /* Note: EMSA-PSS encoding is over the length of N - 1 bits */
+ msb = mbedtls_mpi_bitlen( &ctx->N ) - 1;
+ p += olen - hlen * 2 - 2;
+ *p++ = 0x01;
+ memcpy( p, salt, slen );
+ p += slen;
+
+ mbedtls_md_init( &md_ctx );
+ if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 0 ) ) != 0 )
+ {
+ mbedtls_md_free( &md_ctx );
+ /* No need to zeroize salt: we didn't use it. */
+ return( ret );
+ }
+
+ /* Generate H = Hash( M' ) */
+ mbedtls_md_starts( &md_ctx );
+ mbedtls_md_update( &md_ctx, p, 8 );
+ mbedtls_md_update( &md_ctx, hash, hashlen );
+ mbedtls_md_update( &md_ctx, salt, slen );
+ mbedtls_md_finish( &md_ctx, p );
+ mbedtls_zeroize( salt, sizeof( salt ) );
+
+ /* Compensate for boundary condition when applying mask */
+ if( msb % 8 == 0 )
+ offset = 1;
+
+ /* maskedDB: Apply dbMask to DB */
+ mgf_mask( sig + offset, olen - hlen - 1 - offset, p, hlen, &md_ctx );
+
+ mbedtls_md_free( &md_ctx );
+
+ msb = mbedtls_mpi_bitlen( &ctx->N ) - 1;
+ sig[0] &= 0xFF >> ( olen * 8 - msb );
+
+ p += hlen;
+ *p++ = 0xBC;
+
+ return( ( mode == MBEDTLS_RSA_PUBLIC )
+ ? mbedtls_rsa_public( ctx, sig, sig )
+ : mbedtls_rsa_private( ctx, f_rng, p_rng, sig, sig ) );
+}
+#endif /* MBEDTLS_PKCS1_V21 */
+
+#if defined(MBEDTLS_PKCS1_V15)
+/*
+ * Implementation of the PKCS#1 v2.1 RSASSA-PKCS1-V1_5-SIGN function
+ */
+/*
+ * Do an RSA operation to sign the message digest
+ */
+int mbedtls_rsa_rsassa_pkcs1_v15_sign( mbedtls_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ int mode,
+ mbedtls_md_type_t md_alg,
+ unsigned int hashlen,
+ const unsigned char *hash,
+ unsigned char *sig )
+{
+ size_t nb_pad, olen, oid_size = 0;
+ unsigned char *p = sig;
+ const char *oid = NULL;
+ unsigned char *sig_try = NULL, *verif = NULL;
+ size_t i;
+ unsigned char diff;
+ volatile unsigned char diff_no_optimize;
+ int ret;
+
+ if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 )
+ return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+
+ olen = ctx->len;
+ nb_pad = olen - 3;
+
+ if( md_alg != MBEDTLS_MD_NONE )
+ {
+ const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type( md_alg );
+ if( md_info == NULL )
+ return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+
+ if( mbedtls_oid_get_oid_by_md( md_alg, &oid, &oid_size ) != 0 )
+ return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+
+ nb_pad -= 10 + oid_size;
+
+ hashlen = mbedtls_md_get_size( md_info );
+ }
+
+ nb_pad -= hashlen;
+
+ if( ( nb_pad < 8 ) || ( nb_pad > olen ) )
+ return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+
+ *p++ = 0;
+ *p++ = MBEDTLS_RSA_SIGN;
+ memset( p, 0xFF, nb_pad );
+ p += nb_pad;
+ *p++ = 0;
+
+ if( md_alg == MBEDTLS_MD_NONE )
+ {
+ memcpy( p, hash, hashlen );
+ }
+ else
+ {
+ /*
+ * DigestInfo ::= SEQUENCE {
+ * digestAlgorithm DigestAlgorithmIdentifier,
+ * digest Digest }
+ *
+ * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
+ *
+ * Digest ::= OCTET STRING
+ */
+ *p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED;
+ *p++ = (unsigned char) ( 0x08 + oid_size + hashlen );
+ *p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED;
+ *p++ = (unsigned char) ( 0x04 + oid_size );
+ *p++ = MBEDTLS_ASN1_OID;
+ *p++ = oid_size & 0xFF;
+ memcpy( p, oid, oid_size );
+ p += oid_size;
+ *p++ = MBEDTLS_ASN1_NULL;
+ *p++ = 0x00;
+ *p++ = MBEDTLS_ASN1_OCTET_STRING;
+ *p++ = hashlen;
+ memcpy( p, hash, hashlen );
+ }
+
+ if( mode == MBEDTLS_RSA_PUBLIC )
+ return( mbedtls_rsa_public( ctx, sig, sig ) );
+
+ /*
+ * In order to prevent Lenstra's attack, make the signature in a
+ * temporary buffer and check it before returning it.
+ */
+ sig_try = mbedtls_calloc( 1, ctx->len );
+ if( sig_try == NULL )
+ return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
+
+ verif = mbedtls_calloc( 1, ctx->len );
+ if( verif == NULL )
+ {
+ mbedtls_free( sig_try );
+ return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
+ }
+
+ MBEDTLS_MPI_CHK( mbedtls_rsa_private( ctx, f_rng, p_rng, sig, sig_try ) );
+ MBEDTLS_MPI_CHK( mbedtls_rsa_public( ctx, sig_try, verif ) );
+
+ /* Compare in constant time just in case */
+ for( diff = 0, i = 0; i < ctx->len; i++ )
+ diff |= verif[i] ^ sig[i];
+ diff_no_optimize = diff;
+
+ if( diff_no_optimize != 0 )
+ {
+ ret = MBEDTLS_ERR_RSA_PRIVATE_FAILED;
+ goto cleanup;
+ }
+
+ memcpy( sig, sig_try, ctx->len );
+
+cleanup:
+ mbedtls_free( sig_try );
+ mbedtls_free( verif );
+
+ return( ret );
+}
+#endif /* MBEDTLS_PKCS1_V15 */
+
+/*
+ * Do an RSA operation to sign the message digest
+ */
+int mbedtls_rsa_pkcs1_sign( mbedtls_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ int mode,
+ mbedtls_md_type_t md_alg,
+ unsigned int hashlen,
+ const unsigned char *hash,
+ unsigned char *sig )
+{
+ switch( ctx->padding )
+ {
+#if defined(MBEDTLS_PKCS1_V15)
+ case MBEDTLS_RSA_PKCS_V15:
+ return mbedtls_rsa_rsassa_pkcs1_v15_sign( ctx, f_rng, p_rng, mode, md_alg,
+ hashlen, hash, sig );
+#endif
+
+#if defined(MBEDTLS_PKCS1_V21)
+ case MBEDTLS_RSA_PKCS_V21:
+ return mbedtls_rsa_rsassa_pss_sign( ctx, f_rng, p_rng, mode, md_alg,
+ hashlen, hash, sig );
+#endif
+
+ default:
+ return( MBEDTLS_ERR_RSA_INVALID_PADDING );
+ }
+}
+
+#if defined(MBEDTLS_PKCS1_V21)
+/*
+ * Implementation of the PKCS#1 v2.1 RSASSA-PSS-VERIFY function
+ */
+int mbedtls_rsa_rsassa_pss_verify_ext( mbedtls_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ int mode,
+ mbedtls_md_type_t md_alg,
+ unsigned int hashlen,
+ const unsigned char *hash,
+ mbedtls_md_type_t mgf1_hash_id,
+ int expected_salt_len,
+ const unsigned char *sig )
+{
+ int ret;
+ size_t siglen;
+ unsigned char *p;
+ unsigned char result[MBEDTLS_MD_MAX_SIZE];
+ unsigned char zeros[8];
+ unsigned int hlen;
+ size_t slen, msb;
+ const mbedtls_md_info_t *md_info;
+ mbedtls_md_context_t md_ctx;
+ unsigned char buf[MBEDTLS_MPI_MAX_SIZE];
+
+ if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V21 )
+ return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+
+ siglen = ctx->len;
+
+ if( siglen < 16 || siglen > sizeof( buf ) )
+ return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+
+ ret = ( mode == MBEDTLS_RSA_PUBLIC )
+ ? mbedtls_rsa_public( ctx, sig, buf )
+ : mbedtls_rsa_private( ctx, f_rng, p_rng, sig, buf );
+
+ if( ret != 0 )
+ return( ret );
+
+ p = buf;
+
+ if( buf[siglen - 1] != 0xBC )
+ return( MBEDTLS_ERR_RSA_INVALID_PADDING );
+
+ if( md_alg != MBEDTLS_MD_NONE )
+ {
+ /* Gather length of hash to sign */
+ md_info = mbedtls_md_info_from_type( md_alg );
+ if( md_info == NULL )
+ return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+
+ hashlen = mbedtls_md_get_size( md_info );
+ }
+
+ md_info = mbedtls_md_info_from_type( mgf1_hash_id );
+ if( md_info == NULL )
+ return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+
+ hlen = mbedtls_md_get_size( md_info );
+ slen = siglen - hlen - 1; /* Currently length of salt + padding */
+
+ memset( zeros, 0, 8 );
+
+ /*
+ * Note: EMSA-PSS verification is over the length of N - 1 bits
+ */
+ msb = mbedtls_mpi_bitlen( &ctx->N ) - 1;
+
+ /* Compensate for boundary condition when applying mask */
+ if( msb % 8 == 0 )
+ {
+ p++;
+ siglen -= 1;
+ }
+ if( buf[0] >> ( 8 - siglen * 8 + msb ) )
+ return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+
+ mbedtls_md_init( &md_ctx );
+ if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 0 ) ) != 0 )
+ {
+ mbedtls_md_free( &md_ctx );
+ return( ret );
+ }
+
+ mgf_mask( p, siglen - hlen - 1, p + siglen - hlen - 1, hlen, &md_ctx );
+
+ buf[0] &= 0xFF >> ( siglen * 8 - msb );
+
+ while( p < buf + siglen && *p == 0 )
+ p++;
+
+ if( p == buf + siglen ||
+ *p++ != 0x01 )
+ {
+ mbedtls_md_free( &md_ctx );
+ return( MBEDTLS_ERR_RSA_INVALID_PADDING );
+ }
+
+ /* Actual salt len */
+ slen -= p - buf;
+
+ if( expected_salt_len != MBEDTLS_RSA_SALT_LEN_ANY &&
+ slen != (size_t) expected_salt_len )
+ {
+ mbedtls_md_free( &md_ctx );
+ return( MBEDTLS_ERR_RSA_INVALID_PADDING );
+ }
+
+ /*
+ * Generate H = Hash( M' )
+ */
+ mbedtls_md_starts( &md_ctx );
+ mbedtls_md_update( &md_ctx, zeros, 8 );
+ mbedtls_md_update( &md_ctx, hash, hashlen );
+ mbedtls_md_update( &md_ctx, p, slen );
+ mbedtls_md_finish( &md_ctx, result );
+
+ mbedtls_md_free( &md_ctx );
+
+ if( memcmp( p + slen, result, hlen ) == 0 )
+ return( 0 );
+ else
+ return( MBEDTLS_ERR_RSA_VERIFY_FAILED );
+}
+
+/*
+ * Simplified PKCS#1 v2.1 RSASSA-PSS-VERIFY function
+ */
+int mbedtls_rsa_rsassa_pss_verify( mbedtls_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ int mode,
+ mbedtls_md_type_t md_alg,
+ unsigned int hashlen,
+ const unsigned char *hash,
+ const unsigned char *sig )
+{
+ mbedtls_md_type_t mgf1_hash_id = ( ctx->hash_id != MBEDTLS_MD_NONE )
+ ? (mbedtls_md_type_t) ctx->hash_id
+ : md_alg;
+
+ return( mbedtls_rsa_rsassa_pss_verify_ext( ctx, f_rng, p_rng, mode,
+ md_alg, hashlen, hash,
+ mgf1_hash_id, MBEDTLS_RSA_SALT_LEN_ANY,
+ sig ) );
+
+}
+#endif /* MBEDTLS_PKCS1_V21 */
+
+#if defined(MBEDTLS_PKCS1_V15)
+/*
+ * Implementation of the PKCS#1 v2.1 RSASSA-PKCS1-v1_5-VERIFY function
+ */
+int mbedtls_rsa_rsassa_pkcs1_v15_verify( mbedtls_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ int mode,
+ mbedtls_md_type_t md_alg,
+ unsigned int hashlen,
+ const unsigned char *hash,
+ const unsigned char *sig )
+{
+ int ret;
+ size_t len, siglen, asn1_len;
+ unsigned char *p, *p0, *end;
+ mbedtls_md_type_t msg_md_alg;
+ const mbedtls_md_info_t *md_info;
+ mbedtls_asn1_buf oid;
+ unsigned char buf[MBEDTLS_MPI_MAX_SIZE];
+
+ if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 )
+ return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+
+ siglen = ctx->len;
+
+ if( siglen < 16 || siglen > sizeof( buf ) )
+ return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+
+ ret = ( mode == MBEDTLS_RSA_PUBLIC )
+ ? mbedtls_rsa_public( ctx, sig, buf )
+ : mbedtls_rsa_private( ctx, f_rng, p_rng, sig, buf );
+
+ if( ret != 0 )
+ return( ret );
+
+ p = buf;
+
+ if( *p++ != 0 || *p++ != MBEDTLS_RSA_SIGN )
+ return( MBEDTLS_ERR_RSA_INVALID_PADDING );
+
+ while( *p != 0 )
+ {
+ if( p >= buf + siglen - 1 || *p != 0xFF )
+ return( MBEDTLS_ERR_RSA_INVALID_PADDING );
+ p++;
+ }
+ p++; /* skip 00 byte */
+
+ /* We've read: 00 01 PS 00 where PS must be at least 8 bytes */
+ if( p - buf < 11 )
+ return( MBEDTLS_ERR_RSA_INVALID_PADDING );
+
+ len = siglen - ( p - buf );
+
+ if( len == hashlen && md_alg == MBEDTLS_MD_NONE )
+ {
+ if( memcmp( p, hash, hashlen ) == 0 )
+ return( 0 );
+ else
+ return( MBEDTLS_ERR_RSA_VERIFY_FAILED );
+ }
+
+ md_info = mbedtls_md_info_from_type( md_alg );
+ if( md_info == NULL )
+ return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+ hashlen = mbedtls_md_get_size( md_info );
+
+ end = p + len;
+
+ /*
+ * Parse the ASN.1 structure inside the PKCS#1 v1.5 structure.
+ * Insist on 2-byte length tags, to protect against variants of
+ * Bleichenbacher's forgery attack against lax PKCS#1v1.5 verification.
+ */
+ p0 = p;
+ if( ( ret = mbedtls_asn1_get_tag( &p, end, &asn1_len,
+ MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
+ return( MBEDTLS_ERR_RSA_VERIFY_FAILED );
+ if( p != p0 + 2 || asn1_len + 2 != len )
+ return( MBEDTLS_ERR_RSA_VERIFY_FAILED );
+
+ p0 = p;
+ if( ( ret = mbedtls_asn1_get_tag( &p, end, &asn1_len,
+ MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
+ return( MBEDTLS_ERR_RSA_VERIFY_FAILED );
+ if( p != p0 + 2 || asn1_len + 6 + hashlen != len )
+ return( MBEDTLS_ERR_RSA_VERIFY_FAILED );
+
+ p0 = p;
+ if( ( ret = mbedtls_asn1_get_tag( &p, end, &oid.len, MBEDTLS_ASN1_OID ) ) != 0 )
+ return( MBEDTLS_ERR_RSA_VERIFY_FAILED );
+ if( p != p0 + 2 )
+ return( MBEDTLS_ERR_RSA_VERIFY_FAILED );
+
+ oid.p = p;
+ p += oid.len;
+
+ if( mbedtls_oid_get_md_alg( &oid, &msg_md_alg ) != 0 )
+ return( MBEDTLS_ERR_RSA_VERIFY_FAILED );
+
+ if( md_alg != msg_md_alg )
+ return( MBEDTLS_ERR_RSA_VERIFY_FAILED );
+
+ /*
+ * assume the algorithm parameters must be NULL
+ */
+ p0 = p;
+ if( ( ret = mbedtls_asn1_get_tag( &p, end, &asn1_len, MBEDTLS_ASN1_NULL ) ) != 0 )
+ return( MBEDTLS_ERR_RSA_VERIFY_FAILED );
+ if( p != p0 + 2 )
+ return( MBEDTLS_ERR_RSA_VERIFY_FAILED );
+
+ p0 = p;
+ if( ( ret = mbedtls_asn1_get_tag( &p, end, &asn1_len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 )
+ return( MBEDTLS_ERR_RSA_VERIFY_FAILED );
+ if( p != p0 + 2 || asn1_len != hashlen )
+ return( MBEDTLS_ERR_RSA_VERIFY_FAILED );
+
+ if( memcmp( p, hash, hashlen ) != 0 )
+ return( MBEDTLS_ERR_RSA_VERIFY_FAILED );
+
+ p += hashlen;
+
+ if( p != end )
+ return( MBEDTLS_ERR_RSA_VERIFY_FAILED );
+
+ return( 0 );
+}
+#endif /* MBEDTLS_PKCS1_V15 */
+
+/*
+ * Do an RSA operation and check the message digest
+ */
+int mbedtls_rsa_pkcs1_verify( mbedtls_rsa_context *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ int mode,
+ mbedtls_md_type_t md_alg,
+ unsigned int hashlen,
+ const unsigned char *hash,
+ const unsigned char *sig )
+{
+ switch( ctx->padding )
+ {
+#if defined(MBEDTLS_PKCS1_V15)
+ case MBEDTLS_RSA_PKCS_V15:
+ return mbedtls_rsa_rsassa_pkcs1_v15_verify( ctx, f_rng, p_rng, mode, md_alg,
+ hashlen, hash, sig );
+#endif
+
+#if defined(MBEDTLS_PKCS1_V21)
+ case MBEDTLS_RSA_PKCS_V21:
+ return mbedtls_rsa_rsassa_pss_verify( ctx, f_rng, p_rng, mode, md_alg,
+ hashlen, hash, sig );
+#endif
+
+ default:
+ return( MBEDTLS_ERR_RSA_INVALID_PADDING );
+ }
+}
+
+/*
+ * Copy the components of an RSA key
+ */
+int mbedtls_rsa_copy( mbedtls_rsa_context *dst, const mbedtls_rsa_context *src )
+{
+ int ret;
+
+ dst->ver = src->ver;
+ dst->len = src->len;
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->N, &src->N ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->E, &src->E ) );
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->D, &src->D ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->P, &src->P ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->Q, &src->Q ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->DP, &src->DP ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->DQ, &src->DQ ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->QP, &src->QP ) );
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->RN, &src->RN ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->RP, &src->RP ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->RQ, &src->RQ ) );
+
+ MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->Vi, &src->Vi ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->Vf, &src->Vf ) );
+
+ dst->padding = src->padding;
+ dst->hash_id = src->hash_id;
+
+cleanup:
+ if( ret != 0 )
+ mbedtls_rsa_free( dst );
+
+ return( ret );
+}
+
+/*
+ * Free the components of an RSA key
+ */
+void mbedtls_rsa_free( mbedtls_rsa_context *ctx )
+{
+ mbedtls_mpi_free( &ctx->Vi ); mbedtls_mpi_free( &ctx->Vf );
+ mbedtls_mpi_free( &ctx->RQ ); mbedtls_mpi_free( &ctx->RP ); mbedtls_mpi_free( &ctx->RN );
+ mbedtls_mpi_free( &ctx->QP ); mbedtls_mpi_free( &ctx->DQ ); mbedtls_mpi_free( &ctx->DP );
+ mbedtls_mpi_free( &ctx->Q ); mbedtls_mpi_free( &ctx->P ); mbedtls_mpi_free( &ctx->D );
+ mbedtls_mpi_free( &ctx->E ); mbedtls_mpi_free( &ctx->N );
+
+#if defined(MBEDTLS_THREADING_C)
+ mbedtls_mutex_free( &ctx->mutex );
+#endif
+}
+
+#if defined(MBEDTLS_SELF_TEST)
+
+#include "mbedtls/sha1.h"
+
+/*
+ * Example RSA-1024 keypair, for test purposes
+ */
+#define KEY_LEN 128
+
+#define RSA_N "9292758453063D803DD603D5E777D788" \
+ "8ED1D5BF35786190FA2F23EBC0848AEA" \
+ "DDA92CA6C3D80B32C4D109BE0F36D6AE" \
+ "7130B9CED7ACDF54CFC7555AC14EEBAB" \
+ "93A89813FBF3C4F8066D2D800F7C38A8" \
+ "1AE31942917403FF4946B0A83D3D3E05" \
+ "EE57C6F5F5606FB5D4BC6CD34EE0801A" \
+ "5E94BB77B07507233A0BC7BAC8F90F79"
+
+#define RSA_E "10001"
+
+#define RSA_D "24BF6185468786FDD303083D25E64EFC" \
+ "66CA472BC44D253102F8B4A9D3BFA750" \
+ "91386C0077937FE33FA3252D28855837" \
+ "AE1B484A8A9A45F7EE8C0C634F99E8CD" \
+ "DF79C5CE07EE72C7F123142198164234" \
+ "CABB724CF78B8173B9F880FC86322407" \
+ "AF1FEDFDDE2BEB674CA15F3E81A1521E" \
+ "071513A1E85B5DFA031F21ECAE91A34D"
+
+#define RSA_P "C36D0EB7FCD285223CFB5AABA5BDA3D8" \
+ "2C01CAD19EA484A87EA4377637E75500" \
+ "FCB2005C5C7DD6EC4AC023CDA285D796" \
+ "C3D9E75E1EFC42488BB4F1D13AC30A57"
+
+#define RSA_Q "C000DF51A7C77AE8D7C7370C1FF55B69" \
+ "E211C2B9E5DB1ED0BF61D0D9899620F4" \
+ "910E4168387E3C30AA1E00C339A79508" \
+ "8452DD96A9A5EA5D9DCA68DA636032AF"
+
+#define RSA_DP "C1ACF567564274FB07A0BBAD5D26E298" \
+ "3C94D22288ACD763FD8E5600ED4A702D" \
+ "F84198A5F06C2E72236AE490C93F07F8" \
+ "3CC559CD27BC2D1CA488811730BB5725"
+
+#define RSA_DQ "4959CBF6F8FEF750AEE6977C155579C7" \
+ "D8AAEA56749EA28623272E4F7D0592AF" \
+ "7C1F1313CAC9471B5C523BFE592F517B" \
+ "407A1BD76C164B93DA2D32A383E58357"
+
+#define RSA_QP "9AE7FBC99546432DF71896FC239EADAE" \
+ "F38D18D2B2F0E2DD275AA977E2BF4411" \
+ "F5A3B2A5D33605AEBBCCBA7FEB9F2D2F" \
+ "A74206CEC169D74BF5A8C50D6F48EA08"
+
+#define PT_LEN 24
+#define RSA_PT "\xAA\xBB\xCC\x03\x02\x01\x00\xFF\xFF\xFF\xFF\xFF" \
+ "\x11\x22\x33\x0A\x0B\x0C\xCC\xDD\xDD\xDD\xDD\xDD"
+
+#if defined(MBEDTLS_PKCS1_V15)
+static int myrand( void *rng_state, unsigned char *output, size_t len )
+{
+#if !defined(__OpenBSD__)
+ size_t i;
+
+ if( rng_state != NULL )
+ rng_state = NULL;
+
+ for( i = 0; i < len; ++i )
+ output[i] = rand();
+#else
+ if( rng_state != NULL )
+ rng_state = NULL;
+
+ arc4random_buf( output, len );
+#endif /* !OpenBSD */
+
+ return( 0 );
+}
+#endif /* MBEDTLS_PKCS1_V15 */
+
+/*
+ * Checkup routine
+ */
+int mbedtls_rsa_self_test( int verbose )
+{
+ int ret = 0;
+#if defined(MBEDTLS_PKCS1_V15)
+ size_t len;
+ mbedtls_rsa_context rsa;
+ unsigned char rsa_plaintext[PT_LEN];
+ unsigned char rsa_decrypted[PT_LEN];
+ unsigned char rsa_ciphertext[KEY_LEN];
+#if defined(MBEDTLS_SHA1_C)
+ unsigned char sha1sum[20];
+#endif
+
+ mbedtls_rsa_init( &rsa, MBEDTLS_RSA_PKCS_V15, 0 );
+
+ rsa.len = KEY_LEN;
+ MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &rsa.N , 16, RSA_N ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &rsa.E , 16, RSA_E ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &rsa.D , 16, RSA_D ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &rsa.P , 16, RSA_P ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &rsa.Q , 16, RSA_Q ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &rsa.DP, 16, RSA_DP ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &rsa.DQ, 16, RSA_DQ ) );
+ MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &rsa.QP, 16, RSA_QP ) );
+
+ if( verbose != 0 )
+ mbedtls_printf( " RSA key validation: " );
+
+ if( mbedtls_rsa_check_pubkey( &rsa ) != 0 ||
+ mbedtls_rsa_check_privkey( &rsa ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedtls_printf( "failed\n" );
+
+ return( 1 );
+ }
+
+ if( verbose != 0 )
+ mbedtls_printf( "passed\n PKCS#1 encryption : " );
+
+ memcpy( rsa_plaintext, RSA_PT, PT_LEN );
+
+ if( mbedtls_rsa_pkcs1_encrypt( &rsa, myrand, NULL, MBEDTLS_RSA_PUBLIC, PT_LEN,
+ rsa_plaintext, rsa_ciphertext ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedtls_printf( "failed\n" );
+
+ return( 1 );
+ }
+
+ if( verbose != 0 )
+ mbedtls_printf( "passed\n PKCS#1 decryption : " );
+
+ if( mbedtls_rsa_pkcs1_decrypt( &rsa, myrand, NULL, MBEDTLS_RSA_PRIVATE, &len,
+ rsa_ciphertext, rsa_decrypted,
+ sizeof(rsa_decrypted) ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedtls_printf( "failed\n" );
+
+ return( 1 );
+ }
+
+ if( memcmp( rsa_decrypted, rsa_plaintext, len ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedtls_printf( "failed\n" );
+
+ return( 1 );
+ }
+
+ if( verbose != 0 )
+ mbedtls_printf( "passed\n" );
+
+#if defined(MBEDTLS_SHA1_C)
+ if( verbose != 0 )
+ mbedtls_printf( " PKCS#1 data sign : " );
+
+ mbedtls_sha1( rsa_plaintext, PT_LEN, sha1sum );
+
+ if( mbedtls_rsa_pkcs1_sign( &rsa, myrand, NULL, MBEDTLS_RSA_PRIVATE, MBEDTLS_MD_SHA1, 0,
+ sha1sum, rsa_ciphertext ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedtls_printf( "failed\n" );
+
+ return( 1 );
+ }
+
+ if( verbose != 0 )
+ mbedtls_printf( "passed\n PKCS#1 sig. verify: " );
+
+ if( mbedtls_rsa_pkcs1_verify( &rsa, NULL, NULL, MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA1, 0,
+ sha1sum, rsa_ciphertext ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedtls_printf( "failed\n" );
+
+ return( 1 );
+ }
+
+ if( verbose != 0 )
+ mbedtls_printf( "passed\n" );
+#endif /* MBEDTLS_SHA1_C */
+
+ if( verbose != 0 )
+ mbedtls_printf( "\n" );
+
+cleanup:
+ mbedtls_rsa_free( &rsa );
+#else /* MBEDTLS_PKCS1_V15 */
+ ((void) verbose);
+#endif /* MBEDTLS_PKCS1_V15 */
+ return( ret );
+}
+
+#endif /* MBEDTLS_SELF_TEST */
+
+#endif /* MBEDTLS_RSA_C */
diff --git a/backport/compat/verification/rsapubkey-asn1.c b/backport/compat/verification/rsapubkey-asn1.c
new file mode 100644
index 00000000..84ab7f4e
--- /dev/null
+++ b/backport/compat/verification/rsapubkey-asn1.c
@@ -0,0 +1,38 @@
+/*
+ * Automatically generated by asn1_compiler. Do not edit
+ *
+ * ASN.1 parser for rsapubkey
+ */
+#include <linux/asn1_ber_bytecode.h>
+#include "rsapubkey-asn1.h"
+
+enum rsapubkey_actions {
+ ACT_rsa_get_e = 0,
+ ACT_rsa_get_n = 1,
+ NR__rsapubkey_actions = 2
+};
+
+static const asn1_action_t rsapubkey_action_table[NR__rsapubkey_actions] = {
+ [ 0] = rsa_get_e,
+ [ 1] = rsa_get_n,
+};
+
+static const unsigned char rsapubkey_machine[] = {
+ // RsaPubKey
+ [ 0] = ASN1_OP_MATCH,
+ [ 1] = _tag(UNIV, CONS, SEQ),
+ [ 2] = ASN1_OP_MATCH_ACT, // n
+ [ 3] = _tag(UNIV, PRIM, INT),
+ [ 4] = _action(ACT_rsa_get_n),
+ [ 5] = ASN1_OP_MATCH_ACT, // e
+ [ 6] = _tag(UNIV, PRIM, INT),
+ [ 7] = _action(ACT_rsa_get_e),
+ [ 8] = ASN1_OP_END_SEQ,
+ [ 9] = ASN1_OP_COMPLETE,
+};
+
+const struct asn1_decoder rsapubkey_decoder = {
+ .machine = rsapubkey_machine,
+ .machlen = sizeof(rsapubkey_machine),
+ .actions = rsapubkey_action_table,
+};
diff --git a/backport/compat/verification/rsapubkey-asn1.h b/backport/compat/verification/rsapubkey-asn1.h
new file mode 100644
index 00000000..81a82d40
--- /dev/null
+++ b/backport/compat/verification/rsapubkey-asn1.h
@@ -0,0 +1,15 @@
+/*
+ * Automatically generated by asn1_compiler. Do not edit
+ *
+ * ASN.1 parser for rsapubkey
+ */
+#include <linux/asn1_decoder.h>
+
+extern const struct asn1_decoder rsapubkey_decoder;
+
+#define rsa_get_e LINUX_BACKPORT(rsa_get_e)
+#define rsa_get_n LINUX_BACKPORT(rsa_get_n)
+
+extern int rsa_get_e(void *, size_t, unsigned char, const void *, size_t);
+extern int rsa_get_n(void *, size_t, unsigned char, const void *, size_t);
+
diff --git a/backport/compat/verification/sha256.c b/backport/compat/verification/sha256.c
new file mode 100644
index 00000000..52fedf6a
--- /dev/null
+++ b/backport/compat/verification/sha256.c
@@ -0,0 +1,458 @@
+/*
+ * FIPS-180-2 compliant SHA-256 implementation
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: GPL-2.0
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * This file is part of mbed TLS (https://tls.mbed.org)
+ */
+/*
+ * The SHA-256 Secure Hash Standard was published by NIST in 2002.
+ *
+ * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf
+ */
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "mbedtls/config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#if defined(MBEDTLS_SHA256_C)
+
+#include "mbedtls/sha256.h"
+
+#if defined(MBEDTLS_SELF_TEST)
+#if defined(MBEDTLS_PLATFORM_C)
+#include "mbedtls/platform.h"
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#define mbedtls_printf printf
+#define mbedtls_calloc calloc
+#define mbedtls_free free
+#endif /* MBEDTLS_PLATFORM_C */
+#endif /* MBEDTLS_SELF_TEST */
+
+#if !defined(MBEDTLS_SHA256_ALT)
+
+/* Implementation that should never be optimized out by the compiler */
+static void mbedtls_zeroize( void *v, size_t n ) {
+ volatile unsigned char *p = v; while( n-- ) *p++ = 0;
+}
+
+/*
+ * 32-bit integer manipulation macros (big endian)
+ */
+#ifndef GET_UINT32_BE
+#define GET_UINT32_BE(n,b,i) \
+do { \
+ (n) = ( (uint32_t) (b)[(i) ] << 24 ) \
+ | ( (uint32_t) (b)[(i) + 1] << 16 ) \
+ | ( (uint32_t) (b)[(i) + 2] << 8 ) \
+ | ( (uint32_t) (b)[(i) + 3] ); \
+} while( 0 )
+#endif
+
+#ifndef PUT_UINT32_BE
+#define PUT_UINT32_BE(n,b,i) \
+do { \
+ (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \
+ (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \
+ (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \
+ (b)[(i) + 3] = (unsigned char) ( (n) ); \
+} while( 0 )
+#endif
+
+void mbedtls_sha256_init( mbedtls_sha256_context *ctx )
+{
+ memset( ctx, 0, sizeof( mbedtls_sha256_context ) );
+}
+
+void mbedtls_sha256_free( mbedtls_sha256_context *ctx )
+{
+ if( ctx == NULL )
+ return;
+
+ mbedtls_zeroize( ctx, sizeof( mbedtls_sha256_context ) );
+}
+
+void mbedtls_sha256_clone( mbedtls_sha256_context *dst,
+ const mbedtls_sha256_context *src )
+{
+ *dst = *src;
+}
+
+/*
+ * SHA-256 context setup
+ */
+void mbedtls_sha256_starts( mbedtls_sha256_context *ctx, int is224 )
+{
+ ctx->total[0] = 0;
+ ctx->total[1] = 0;
+
+ if( is224 == 0 )
+ {
+ /* SHA-256 */
+ ctx->state[0] = 0x6A09E667;
+ ctx->state[1] = 0xBB67AE85;
+ ctx->state[2] = 0x3C6EF372;
+ ctx->state[3] = 0xA54FF53A;
+ ctx->state[4] = 0x510E527F;
+ ctx->state[5] = 0x9B05688C;
+ ctx->state[6] = 0x1F83D9AB;
+ ctx->state[7] = 0x5BE0CD19;
+ }
+ else
+ {
+ /* SHA-224 */
+ ctx->state[0] = 0xC1059ED8;
+ ctx->state[1] = 0x367CD507;
+ ctx->state[2] = 0x3070DD17;
+ ctx->state[3] = 0xF70E5939;
+ ctx->state[4] = 0xFFC00B31;
+ ctx->state[5] = 0x68581511;
+ ctx->state[6] = 0x64F98FA7;
+ ctx->state[7] = 0xBEFA4FA4;
+ }
+
+ ctx->is224 = is224;
+}
+
+#if !defined(MBEDTLS_SHA256_PROCESS_ALT)
+static const uint32_t K[] =
+{
+ 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5,
+ 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,
+ 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3,
+ 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,
+ 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC,
+ 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,
+ 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7,
+ 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,
+ 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13,
+ 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,
+ 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3,
+ 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,
+ 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5,
+ 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,
+ 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208,
+ 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2,
+};
+
+#define SHR(x,n) ((x & 0xFFFFFFFF) >> n)
+#define ROTR(x,n) (SHR(x,n) | (x << (32 - n)))
+
+#define S0(x) (ROTR(x, 7) ^ ROTR(x,18) ^ SHR(x, 3))
+#define S1(x) (ROTR(x,17) ^ ROTR(x,19) ^ SHR(x,10))
+
+#define S2(x) (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x,22))
+#define S3(x) (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x,25))
+
+#define F0(x,y,z) ((x & y) | (z & (x | y)))
+#define F1(x,y,z) (z ^ (x & (y ^ z)))
+
+#define R(t) \
+( \
+ W[t] = S1(W[t - 2]) + W[t - 7] + \
+ S0(W[t - 15]) + W[t - 16] \
+)
+
+#define P(a,b,c,d,e,f,g,h,x,K) \
+{ \
+ temp1 = h + S3(e) + F1(e,f,g) + K + x; \
+ temp2 = S2(a) + F0(a,b,c); \
+ d += temp1; h = temp1 + temp2; \
+}
+
+void mbedtls_sha256_process( mbedtls_sha256_context *ctx, const unsigned char data[64] )
+{
+ uint32_t temp1, temp2, W[64];
+ uint32_t A[8];
+ unsigned int i;
+
+ for( i = 0; i < 8; i++ )
+ A[i] = ctx->state[i];
+
+#if defined(MBEDTLS_SHA256_SMALLER)
+ for( i = 0; i < 64; i++ )
+ {
+ if( i < 16 )
+ GET_UINT32_BE( W[i], data, 4 * i );
+ else
+ R( i );
+
+ P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i], K[i] );
+
+ temp1 = A[7]; A[7] = A[6]; A[6] = A[5]; A[5] = A[4]; A[4] = A[3];
+ A[3] = A[2]; A[2] = A[1]; A[1] = A[0]; A[0] = temp1;
+ }
+#else /* MBEDTLS_SHA256_SMALLER */
+ for( i = 0; i < 16; i++ )
+ GET_UINT32_BE( W[i], data, 4 * i );
+
+ for( i = 0; i < 16; i += 8 )
+ {
+ P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i+0], K[i+0] );
+ P( A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], W[i+1], K[i+1] );
+ P( A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], W[i+2], K[i+2] );
+ P( A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], W[i+3], K[i+3] );
+ P( A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], W[i+4], K[i+4] );
+ P( A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], W[i+5], K[i+5] );
+ P( A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], W[i+6], K[i+6] );
+ P( A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], W[i+7], K[i+7] );
+ }
+
+ for( i = 16; i < 64; i += 8 )
+ {
+ P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(i+0), K[i+0] );
+ P( A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(i+1), K[i+1] );
+ P( A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(i+2), K[i+2] );
+ P( A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(i+3), K[i+3] );
+ P( A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(i+4), K[i+4] );
+ P( A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(i+5), K[i+5] );
+ P( A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(i+6), K[i+6] );
+ P( A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(i+7), K[i+7] );
+ }
+#endif /* MBEDTLS_SHA256_SMALLER */
+
+ for( i = 0; i < 8; i++ )
+ ctx->state[i] += A[i];
+}
+#endif /* !MBEDTLS_SHA256_PROCESS_ALT */
+
+/*
+ * SHA-256 process buffer
+ */
+void mbedtls_sha256_update( mbedtls_sha256_context *ctx, const unsigned char *input,
+ size_t ilen )
+{
+ size_t fill;
+ uint32_t left;
+
+ if( ilen == 0 )
+ return;
+
+ left = ctx->total[0] & 0x3F;
+ fill = 64 - left;
+
+ ctx->total[0] += (uint32_t) ilen;
+ ctx->total[0] &= 0xFFFFFFFF;
+
+ if( ctx->total[0] < (uint32_t) ilen )
+ ctx->total[1]++;
+
+ if( left && ilen >= fill )
+ {
+ memcpy( (void *) (ctx->buffer + left), input, fill );
+ mbedtls_sha256_process( ctx, ctx->buffer );
+ input += fill;
+ ilen -= fill;
+ left = 0;
+ }
+
+ while( ilen >= 64 )
+ {
+ mbedtls_sha256_process( ctx, input );
+ input += 64;
+ ilen -= 64;
+ }
+
+ if( ilen > 0 )
+ memcpy( (void *) (ctx->buffer + left), input, ilen );
+}
+
+static const unsigned char sha256_padding[64] =
+{
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/*
+ * SHA-256 final digest
+ */
+void mbedtls_sha256_finish( mbedtls_sha256_context *ctx, unsigned char output[32] )
+{
+ uint32_t last, padn;
+ uint32_t high, low;
+ unsigned char msglen[8];
+
+ high = ( ctx->total[0] >> 29 )
+ | ( ctx->total[1] << 3 );
+ low = ( ctx->total[0] << 3 );
+
+ PUT_UINT32_BE( high, msglen, 0 );
+ PUT_UINT32_BE( low, msglen, 4 );
+
+ last = ctx->total[0] & 0x3F;
+ padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
+
+ mbedtls_sha256_update( ctx, sha256_padding, padn );
+ mbedtls_sha256_update( ctx, msglen, 8 );
+
+ PUT_UINT32_BE( ctx->state[0], output, 0 );
+ PUT_UINT32_BE( ctx->state[1], output, 4 );
+ PUT_UINT32_BE( ctx->state[2], output, 8 );
+ PUT_UINT32_BE( ctx->state[3], output, 12 );
+ PUT_UINT32_BE( ctx->state[4], output, 16 );
+ PUT_UINT32_BE( ctx->state[5], output, 20 );
+ PUT_UINT32_BE( ctx->state[6], output, 24 );
+
+ if( ctx->is224 == 0 )
+ PUT_UINT32_BE( ctx->state[7], output, 28 );
+}
+
+#endif /* !MBEDTLS_SHA256_ALT */
+
+/*
+ * output = SHA-256( input buffer )
+ */
+void mbedtls_sha256( const unsigned char *input, size_t ilen,
+ unsigned char output[32], int is224 )
+{
+ mbedtls_sha256_context ctx;
+
+ mbedtls_sha256_init( &ctx );
+ mbedtls_sha256_starts( &ctx, is224 );
+ mbedtls_sha256_update( &ctx, input, ilen );
+ mbedtls_sha256_finish( &ctx, output );
+ mbedtls_sha256_free( &ctx );
+}
+
+#if defined(MBEDTLS_SELF_TEST)
+/*
+ * FIPS-180-2 test vectors
+ */
+static const unsigned char sha256_test_buf[3][57] =
+{
+ { "abc" },
+ { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" },
+ { "" }
+};
+
+static const int sha256_test_buflen[3] =
+{
+ 3, 56, 1000
+};
+
+static const unsigned char sha256_test_sum[6][32] =
+{
+ /*
+ * SHA-224 test vectors
+ */
+ { 0x23, 0x09, 0x7D, 0x22, 0x34, 0x05, 0xD8, 0x22,
+ 0x86, 0x42, 0xA4, 0x77, 0xBD, 0xA2, 0x55, 0xB3,
+ 0x2A, 0xAD, 0xBC, 0xE4, 0xBD, 0xA0, 0xB3, 0xF7,
+ 0xE3, 0x6C, 0x9D, 0xA7 },
+ { 0x75, 0x38, 0x8B, 0x16, 0x51, 0x27, 0x76, 0xCC,
+ 0x5D, 0xBA, 0x5D, 0xA1, 0xFD, 0x89, 0x01, 0x50,
+ 0xB0, 0xC6, 0x45, 0x5C, 0xB4, 0xF5, 0x8B, 0x19,
+ 0x52, 0x52, 0x25, 0x25 },
+ { 0x20, 0x79, 0x46, 0x55, 0x98, 0x0C, 0x91, 0xD8,
+ 0xBB, 0xB4, 0xC1, 0xEA, 0x97, 0x61, 0x8A, 0x4B,
+ 0xF0, 0x3F, 0x42, 0x58, 0x19, 0x48, 0xB2, 0xEE,
+ 0x4E, 0xE7, 0xAD, 0x67 },
+
+ /*
+ * SHA-256 test vectors
+ */
+ { 0xBA, 0x78, 0x16, 0xBF, 0x8F, 0x01, 0xCF, 0xEA,
+ 0x41, 0x41, 0x40, 0xDE, 0x5D, 0xAE, 0x22, 0x23,
+ 0xB0, 0x03, 0x61, 0xA3, 0x96, 0x17, 0x7A, 0x9C,
+ 0xB4, 0x10, 0xFF, 0x61, 0xF2, 0x00, 0x15, 0xAD },
+ { 0x24, 0x8D, 0x6A, 0x61, 0xD2, 0x06, 0x38, 0xB8,
+ 0xE5, 0xC0, 0x26, 0x93, 0x0C, 0x3E, 0x60, 0x39,
+ 0xA3, 0x3C, 0xE4, 0x59, 0x64, 0xFF, 0x21, 0x67,
+ 0xF6, 0xEC, 0xED, 0xD4, 0x19, 0xDB, 0x06, 0xC1 },
+ { 0xCD, 0xC7, 0x6E, 0x5C, 0x99, 0x14, 0xFB, 0x92,
+ 0x81, 0xA1, 0xC7, 0xE2, 0x84, 0xD7, 0x3E, 0x67,
+ 0xF1, 0x80, 0x9A, 0x48, 0xA4, 0x97, 0x20, 0x0E,
+ 0x04, 0x6D, 0x39, 0xCC, 0xC7, 0x11, 0x2C, 0xD0 }
+};
+
+/*
+ * Checkup routine
+ */
+int mbedtls_sha256_self_test( int verbose )
+{
+ int i, j, k, buflen, ret = 0;
+ unsigned char *buf;
+ unsigned char sha256sum[32];
+ mbedtls_sha256_context ctx;
+
+ buf = mbedtls_calloc( 1024, sizeof(unsigned char) );
+ if( NULL == buf )
+ {
+ if( verbose != 0 )
+ mbedtls_printf( "Buffer allocation failed\n" );
+
+ return( 1 );
+ }
+
+ mbedtls_sha256_init( &ctx );
+
+ for( i = 0; i < 6; i++ )
+ {
+ j = i % 3;
+ k = i < 3;
+
+ if( verbose != 0 )
+ mbedtls_printf( " SHA-%d test #%d: ", 256 - k * 32, j + 1 );
+
+ mbedtls_sha256_starts( &ctx, k );
+
+ if( j == 2 )
+ {
+ memset( buf, 'a', buflen = 1000 );
+
+ for( j = 0; j < 1000; j++ )
+ mbedtls_sha256_update( &ctx, buf, buflen );
+ }
+ else
+ mbedtls_sha256_update( &ctx, sha256_test_buf[j],
+ sha256_test_buflen[j] );
+
+ mbedtls_sha256_finish( &ctx, sha256sum );
+
+ if( memcmp( sha256sum, sha256_test_sum[i], 32 - k * 4 ) != 0 )
+ {
+ if( verbose != 0 )
+ mbedtls_printf( "failed\n" );
+
+ ret = 1;
+ goto exit;
+ }
+
+ if( verbose != 0 )
+ mbedtls_printf( "passed\n" );
+ }
+
+ if( verbose != 0 )
+ mbedtls_printf( "\n" );
+
+exit:
+ mbedtls_sha256_free( &ctx );
+ mbedtls_free( buf );
+
+ return( ret );
+}
+
+#endif /* MBEDTLS_SELF_TEST */
+
+#endif /* MBEDTLS_SHA256_C */
diff --git a/backport/compat/verification/verify.c b/backport/compat/verification/verify.c
new file mode 100644
index 00000000..6f686a63
--- /dev/null
+++ b/backport/compat/verification/verify.c
@@ -0,0 +1,65 @@
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/verification.h>
+#include <linux/export.h>
+#include <linux/err.h>
+#include <crypto/pkcs7.h>
+
+int verify_pkcs7_signature(const void *data, size_t len,
+ const void *raw_pkcs7, size_t pkcs7_len,
+ struct key *trusted_keys,
+ enum key_being_used_for usage,
+ int (*view_content)(void *ctx,
+ const void *data, size_t len,
+ size_t asn1hdrlen),
+ void *ctx)
+{
+ struct pkcs7_message *pkcs7;
+ int ret;
+
+ pkcs7 = pkcs7_parse_message(raw_pkcs7, pkcs7_len);
+ if (IS_ERR(pkcs7))
+ return PTR_ERR(pkcs7);
+
+ /* The data should be detached - so we need to supply it. */
+ if (data && pkcs7_supply_detached_data(pkcs7, data, len) < 0) {
+ pr_err("PKCS#7 signature with non-detached data\n");
+ ret = -EBADMSG;
+ goto error;
+ }
+
+ ret = pkcs7_verify(pkcs7, usage);
+ if (ret < 0)
+ goto error;
+
+ if (WARN_ON(!trusted_keys)) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ ret = pkcs7_validate_trust(pkcs7, trusted_keys);
+ if (ret < 0) {
+ if (ret == -ENOKEY)
+ pr_err("PKCS#7 signature not signed with a trusted key\n");
+ goto error;
+ }
+
+ if (view_content) {
+ size_t asn1hdrlen;
+
+ ret = pkcs7_get_content_data(pkcs7, &data, &len, &asn1hdrlen);
+ if (ret < 0) {
+ if (ret == -ENODATA)
+ pr_devel("PKCS#7 message does not contain data\n");
+ goto error;
+ }
+
+ ret = view_content(ctx, data, len, asn1hdrlen);
+ }
+
+error:
+ pkcs7_free_message(pkcs7);
+ pr_devel("<==%s() = %d\n", __func__, ret);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(verify_pkcs7_signature);
diff --git a/backport/compat/verification/x509-asn1.c b/backport/compat/verification/x509-asn1.c
new file mode 100644
index 00000000..89aaa662
--- /dev/null
+++ b/backport/compat/verification/x509-asn1.c
@@ -0,0 +1,182 @@
+/*
+ * Automatically generated by asn1_compiler. Do not edit
+ *
+ * ASN.1 parser for x509
+ */
+#include <linux/asn1_ber_bytecode.h>
+#include "x509-asn1.h"
+
+enum x509_actions {
+ ACT_x509_extract_key_data = 0,
+ ACT_x509_extract_name_segment = 1,
+ ACT_x509_note_OID = 2,
+ ACT_x509_note_issuer = 3,
+ ACT_x509_note_not_after = 4,
+ ACT_x509_note_not_before = 5,
+ ACT_x509_note_pkey_algo = 6,
+ ACT_x509_note_serial = 7,
+ ACT_x509_note_signature = 8,
+ ACT_x509_note_subject = 9,
+ ACT_x509_note_tbs_certificate = 10,
+ ACT_x509_process_extension = 11,
+ NR__x509_actions = 12
+};
+
+static const asn1_action_t x509_action_table[NR__x509_actions] = {
+ [ 0] = x509_extract_key_data,
+ [ 1] = x509_extract_name_segment,
+ [ 2] = x509_note_OID,
+ [ 3] = x509_note_issuer,
+ [ 4] = x509_note_not_after,
+ [ 5] = x509_note_not_before,
+ [ 6] = x509_note_pkey_algo,
+ [ 7] = x509_note_serial,
+ [ 8] = x509_note_signature,
+ [ 9] = x509_note_subject,
+ [ 10] = x509_note_tbs_certificate,
+ [ 11] = x509_process_extension,
+};
+
+static const unsigned char x509_machine[] = {
+ // Certificate
+ [ 0] = ASN1_OP_MATCH,
+ [ 1] = _tag(UNIV, CONS, SEQ),
+ // TBSCertificate
+ [ 2] = ASN1_OP_MATCH,
+ [ 3] = _tag(UNIV, CONS, SEQ),
+ [ 4] = ASN1_OP_MATCH_JUMP_OR_SKIP, // version
+ [ 5] = _tagn(CONT, CONS, 0),
+ [ 6] = _jump_target(70),
+ // CertificateSerialNumber
+ [ 7] = ASN1_OP_MATCH,
+ [ 8] = _tag(UNIV, PRIM, INT),
+ [ 9] = ASN1_OP_ACT,
+ [ 10] = _action(ACT_x509_note_serial),
+ // AlgorithmIdentifier
+ [ 11] = ASN1_OP_MATCH_JUMP,
+ [ 12] = _tag(UNIV, CONS, SEQ),
+ [ 13] = _jump_target(74), // --> AlgorithmIdentifier
+ [ 14] = ASN1_OP_ACT,
+ [ 15] = _action(ACT_x509_note_pkey_algo),
+ // Name
+ [ 16] = ASN1_OP_MATCH_JUMP,
+ [ 17] = _tag(UNIV, CONS, SEQ),
+ [ 18] = _jump_target(80), // --> Name
+ [ 19] = ASN1_OP_ACT,
+ [ 20] = _action(ACT_x509_note_issuer),
+ // Validity
+ [ 21] = ASN1_OP_MATCH,
+ [ 22] = _tag(UNIV, CONS, SEQ),
+ // Time
+ [ 23] = ASN1_OP_MATCH_OR_SKIP, // utcTime
+ [ 24] = _tag(UNIV, PRIM, UNITIM),
+ [ 25] = ASN1_OP_COND_MATCH_OR_SKIP, // generalTime
+ [ 26] = _tag(UNIV, PRIM, GENTIM),
+ [ 27] = ASN1_OP_COND_FAIL,
+ [ 28] = ASN1_OP_ACT,
+ [ 29] = _action(ACT_x509_note_not_before),
+ // Time
+ [ 30] = ASN1_OP_MATCH_OR_SKIP, // utcTime
+ [ 31] = _tag(UNIV, PRIM, UNITIM),
+ [ 32] = ASN1_OP_COND_MATCH_OR_SKIP, // generalTime
+ [ 33] = _tag(UNIV, PRIM, GENTIM),
+ [ 34] = ASN1_OP_COND_FAIL,
+ [ 35] = ASN1_OP_ACT,
+ [ 36] = _action(ACT_x509_note_not_after),
+ [ 37] = ASN1_OP_END_SEQ,
+ // Name
+ [ 38] = ASN1_OP_MATCH_JUMP,
+ [ 39] = _tag(UNIV, CONS, SEQ),
+ [ 40] = _jump_target(80), // --> Name
+ [ 41] = ASN1_OP_ACT,
+ [ 42] = _action(ACT_x509_note_subject),
+ // SubjectPublicKeyInfo
+ [ 43] = ASN1_OP_MATCH,
+ [ 44] = _tag(UNIV, CONS, SEQ),
+ // AlgorithmIdentifier
+ [ 45] = ASN1_OP_MATCH_JUMP,
+ [ 46] = _tag(UNIV, CONS, SEQ),
+ [ 47] = _jump_target(74), // --> AlgorithmIdentifier
+ [ 48] = ASN1_OP_MATCH_ACT, // subjectPublicKey
+ [ 49] = _tag(UNIV, PRIM, BTS),
+ [ 50] = _action(ACT_x509_extract_key_data),
+ [ 51] = ASN1_OP_END_SEQ,
+ // UniqueIdentifier
+ [ 52] = ASN1_OP_MATCH_OR_SKIP, // issuerUniqueID
+ [ 53] = _tagn(CONT, PRIM, 1),
+ // UniqueIdentifier
+ [ 54] = ASN1_OP_MATCH_OR_SKIP, // subjectUniqueID
+ [ 55] = _tagn(CONT, PRIM, 2),
+ [ 56] = ASN1_OP_MATCH_JUMP_OR_SKIP, // extensions
+ [ 57] = _tagn(CONT, CONS, 3),
+ [ 58] = _jump_target(95),
+ [ 59] = ASN1_OP_END_SEQ,
+ [ 60] = ASN1_OP_ACT,
+ [ 61] = _action(ACT_x509_note_tbs_certificate),
+ // AlgorithmIdentifier
+ [ 62] = ASN1_OP_MATCH_JUMP,
+ [ 63] = _tag(UNIV, CONS, SEQ),
+ [ 64] = _jump_target(74), // --> AlgorithmIdentifier
+ [ 65] = ASN1_OP_MATCH_ACT, // signature
+ [ 66] = _tag(UNIV, PRIM, BTS),
+ [ 67] = _action(ACT_x509_note_signature),
+ [ 68] = ASN1_OP_END_SEQ,
+ [ 69] = ASN1_OP_COMPLETE,
+
+ // Version
+ [ 70] = ASN1_OP_MATCH,
+ [ 71] = _tag(UNIV, PRIM, INT),
+ [ 72] = ASN1_OP_END_SEQ,
+ [ 73] = ASN1_OP_RETURN,
+
+ [ 74] = ASN1_OP_MATCH_ACT, // algorithm
+ [ 75] = _tag(UNIV, PRIM, OID),
+ [ 76] = _action(ACT_x509_note_OID),
+ [ 77] = ASN1_OP_MATCH_ANY_OR_SKIP, // parameters
+ [ 78] = ASN1_OP_END_SEQ,
+ [ 79] = ASN1_OP_RETURN,
+
+ // RelativeDistinguishedName
+ [ 80] = ASN1_OP_MATCH,
+ [ 81] = _tag(UNIV, CONS, SET),
+ // AttributeValueAssertion
+ [ 82] = ASN1_OP_MATCH,
+ [ 83] = _tag(UNIV, CONS, SEQ),
+ [ 84] = ASN1_OP_MATCH_ACT, // attributeType
+ [ 85] = _tag(UNIV, PRIM, OID),
+ [ 86] = _action(ACT_x509_note_OID),
+ [ 87] = ASN1_OP_MATCH_ANY_ACT, // attributeValue
+ [ 88] = _action(ACT_x509_extract_name_segment),
+ [ 89] = ASN1_OP_END_SEQ,
+ [ 90] = ASN1_OP_END_SET_OF,
+ [ 91] = _jump_target(82),
+ [ 92] = ASN1_OP_END_SEQ_OF,
+ [ 93] = _jump_target(80),
+ [ 94] = ASN1_OP_RETURN,
+
+ // Extensions
+ [ 95] = ASN1_OP_MATCH,
+ [ 96] = _tag(UNIV, CONS, SEQ),
+ // Extension
+ [ 97] = ASN1_OP_MATCH,
+ [ 98] = _tag(UNIV, CONS, SEQ),
+ [ 99] = ASN1_OP_MATCH_ACT, // extnid
+ [ 100] = _tag(UNIV, PRIM, OID),
+ [ 101] = _action(ACT_x509_note_OID),
+ [ 102] = ASN1_OP_MATCH_OR_SKIP, // critical
+ [ 103] = _tag(UNIV, PRIM, BOOL),
+ [ 104] = ASN1_OP_MATCH_ACT, // extnValue
+ [ 105] = _tag(UNIV, PRIM, OTS),
+ [ 106] = _action(ACT_x509_process_extension),
+ [ 107] = ASN1_OP_END_SEQ,
+ [ 108] = ASN1_OP_END_SEQ_OF,
+ [ 109] = _jump_target(97),
+ [ 110] = ASN1_OP_END_SEQ,
+ [ 111] = ASN1_OP_RETURN,
+};
+
+const struct asn1_decoder x509_decoder = {
+ .machine = x509_machine,
+ .machlen = sizeof(x509_machine),
+ .actions = x509_action_table,
+};
diff --git a/backport/compat/verification/x509-asn1.h b/backport/compat/verification/x509-asn1.h
new file mode 100644
index 00000000..4f32a25d
--- /dev/null
+++ b/backport/compat/verification/x509-asn1.h
@@ -0,0 +1,22 @@
+/*
+ * Automatically generated by asn1_compiler. Do not edit
+ *
+ * ASN.1 parser for x509
+ */
+#include <linux/asn1_decoder.h>
+
+extern const struct asn1_decoder x509_decoder;
+
+extern int x509_extract_key_data(void *, size_t, unsigned char, const void *, size_t);
+extern int x509_extract_name_segment(void *, size_t, unsigned char, const void *, size_t);
+extern int x509_note_OID(void *, size_t, unsigned char, const void *, size_t);
+extern int x509_note_issuer(void *, size_t, unsigned char, const void *, size_t);
+extern int x509_note_not_after(void *, size_t, unsigned char, const void *, size_t);
+extern int x509_note_not_before(void *, size_t, unsigned char, const void *, size_t);
+extern int x509_note_pkey_algo(void *, size_t, unsigned char, const void *, size_t);
+extern int x509_note_serial(void *, size_t, unsigned char, const void *, size_t);
+extern int x509_note_signature(void *, size_t, unsigned char, const void *, size_t);
+extern int x509_note_subject(void *, size_t, unsigned char, const void *, size_t);
+extern int x509_note_tbs_certificate(void *, size_t, unsigned char, const void *, size_t);
+extern int x509_process_extension(void *, size_t, unsigned char, const void *, size_t);
+
diff --git a/backport/compat/verification/x509_akid-asn1.c b/backport/compat/verification/x509_akid-asn1.c
new file mode 100644
index 00000000..dd3c6c2e
--- /dev/null
+++ b/backport/compat/verification/x509_akid-asn1.c
@@ -0,0 +1,144 @@
+/*
+ * Automatically generated by asn1_compiler. Do not edit
+ *
+ * ASN.1 parser for x509_akid
+ */
+#include <linux/asn1_ber_bytecode.h>
+#include "x509_akid-asn1.h"
+
+enum x509_akid_actions {
+ ACT_x509_akid_note_kid = 0,
+ ACT_x509_akid_note_name = 1,
+ ACT_x509_akid_note_serial = 2,
+ ACT_x509_extract_name_segment = 3,
+ ACT_x509_note_OID = 4,
+ NR__x509_akid_actions = 5
+};
+
+static const asn1_action_t x509_akid_action_table[NR__x509_akid_actions] = {
+ [ 0] = x509_akid_note_kid,
+ [ 1] = x509_akid_note_name,
+ [ 2] = x509_akid_note_serial,
+ [ 3] = x509_extract_name_segment,
+ [ 4] = x509_note_OID,
+};
+
+static const unsigned char x509_akid_machine[] = {
+ // AuthorityKeyIdentifier
+ [ 0] = ASN1_OP_MATCH,
+ [ 1] = _tag(UNIV, CONS, SEQ),
+ // KeyIdentifier
+ [ 2] = ASN1_OP_MATCH_ACT_OR_SKIP, // keyIdentifier
+ [ 3] = _tagn(CONT, PRIM, 0),
+ [ 4] = _action(ACT_x509_akid_note_kid),
+ // GeneralNames
+ [ 5] = ASN1_OP_MATCH_JUMP_OR_SKIP, // authorityCertIssuer
+ [ 6] = _tagn(CONT, CONS, 1),
+ [ 7] = _jump_target(13), // --> GeneralNames
+ // CertificateSerialNumber
+ [ 8] = ASN1_OP_MATCH_ACT_OR_SKIP, // authorityCertSerialNumber
+ [ 9] = _tagn(CONT, PRIM, 2),
+ [ 10] = _action(ACT_x509_akid_note_serial),
+ [ 11] = ASN1_OP_END_SEQ,
+ [ 12] = ASN1_OP_COMPLETE,
+
+ // GeneralName
+ [ 13] = ASN1_OP_MATCH_JUMP_OR_SKIP, // otherName
+ [ 14] = _tagn(CONT, CONS, 0),
+ [ 15] = _jump_target(44),
+ [ 16] = ASN1_OP_COND_MATCH_JUMP_OR_SKIP, // rfc822Name
+ [ 17] = _tagn(CONT, CONS, 1),
+ [ 18] = _jump_target(47),
+ [ 19] = ASN1_OP_COND_MATCH_JUMP_OR_SKIP, // dNSName
+ [ 20] = _tagn(CONT, CONS, 2),
+ [ 21] = _jump_target(51),
+ [ 22] = ASN1_OP_COND_MATCH_JUMP_OR_SKIP, // x400Address
+ [ 23] = _tagn(CONT, CONS, 3),
+ [ 24] = _jump_target(55),
+ [ 25] = ASN1_OP_COND_MATCH_JUMP_OR_SKIP, // directoryName
+ [ 26] = _tagn(CONT, CONS, 4),
+ [ 27] = _jump_target(58),
+ [ 28] = ASN1_OP_COND_MATCH_JUMP_OR_SKIP, // ediPartyName
+ [ 29] = _tagn(CONT, CONS, 5),
+ [ 30] = _jump_target(78),
+ [ 31] = ASN1_OP_COND_MATCH_JUMP_OR_SKIP, // uniformResourceIdentifier
+ [ 32] = _tagn(CONT, CONS, 6),
+ [ 33] = _jump_target(81),
+ [ 34] = ASN1_OP_COND_MATCH_JUMP_OR_SKIP, // iPAddress
+ [ 35] = _tagn(CONT, CONS, 7),
+ [ 36] = _jump_target(85),
+ [ 37] = ASN1_OP_COND_MATCH_JUMP_OR_SKIP, // registeredID
+ [ 38] = _tagn(CONT, CONS, 8),
+ [ 39] = _jump_target(89),
+ [ 40] = ASN1_OP_COND_FAIL,
+ [ 41] = ASN1_OP_END_SEQ_OF,
+ [ 42] = _jump_target(13),
+ [ 43] = ASN1_OP_RETURN,
+
+ [ 44] = ASN1_OP_MATCH_ANY, // otherName
+ [ 45] = ASN1_OP_END_SEQ,
+ [ 46] = ASN1_OP_RETURN,
+
+ [ 47] = ASN1_OP_MATCH, // rfc822Name
+ [ 48] = _tag(UNIV, PRIM, IA5STR),
+ [ 49] = ASN1_OP_END_SEQ,
+ [ 50] = ASN1_OP_RETURN,
+
+ [ 51] = ASN1_OP_MATCH, // dNSName
+ [ 52] = _tag(UNIV, PRIM, IA5STR),
+ [ 53] = ASN1_OP_END_SEQ,
+ [ 54] = ASN1_OP_RETURN,
+
+ [ 55] = ASN1_OP_MATCH_ANY, // x400Address
+ [ 56] = ASN1_OP_END_SEQ,
+ [ 57] = ASN1_OP_RETURN,
+
+ // Name
+ [ 58] = ASN1_OP_MATCH,
+ [ 59] = _tag(UNIV, CONS, SEQ),
+ // RelativeDistinguishedName
+ [ 60] = ASN1_OP_MATCH,
+ [ 61] = _tag(UNIV, CONS, SET),
+ // AttributeValueAssertion
+ [ 62] = ASN1_OP_MATCH,
+ [ 63] = _tag(UNIV, CONS, SEQ),
+ [ 64] = ASN1_OP_MATCH_ACT, // attributeType
+ [ 65] = _tag(UNIV, PRIM, OID),
+ [ 66] = _action(ACT_x509_note_OID),
+ [ 67] = ASN1_OP_MATCH_ANY_ACT, // attributeValue
+ [ 68] = _action(ACT_x509_extract_name_segment),
+ [ 69] = ASN1_OP_END_SEQ,
+ [ 70] = ASN1_OP_END_SET_OF,
+ [ 71] = _jump_target(62),
+ [ 72] = ASN1_OP_END_SEQ_OF,
+ [ 73] = _jump_target(60),
+ [ 74] = ASN1_OP_ACT,
+ [ 75] = _action(ACT_x509_akid_note_name),
+ [ 76] = ASN1_OP_END_SEQ,
+ [ 77] = ASN1_OP_RETURN,
+
+ [ 78] = ASN1_OP_MATCH_ANY, // ediPartyName
+ [ 79] = ASN1_OP_END_SEQ,
+ [ 80] = ASN1_OP_RETURN,
+
+ [ 81] = ASN1_OP_MATCH, // uniformResourceIdentifier
+ [ 82] = _tag(UNIV, PRIM, IA5STR),
+ [ 83] = ASN1_OP_END_SEQ,
+ [ 84] = ASN1_OP_RETURN,
+
+ [ 85] = ASN1_OP_MATCH, // iPAddress
+ [ 86] = _tag(UNIV, PRIM, OTS),
+ [ 87] = ASN1_OP_END_SEQ,
+ [ 88] = ASN1_OP_RETURN,
+
+ [ 89] = ASN1_OP_MATCH, // registeredID
+ [ 90] = _tag(UNIV, PRIM, OID),
+ [ 91] = ASN1_OP_END_SEQ,
+ [ 92] = ASN1_OP_RETURN,
+};
+
+const struct asn1_decoder x509_akid_decoder = {
+ .machine = x509_akid_machine,
+ .machlen = sizeof(x509_akid_machine),
+ .actions = x509_akid_action_table,
+};
diff --git a/backport/compat/verification/x509_akid-asn1.h b/backport/compat/verification/x509_akid-asn1.h
new file mode 100644
index 00000000..92914da5
--- /dev/null
+++ b/backport/compat/verification/x509_akid-asn1.h
@@ -0,0 +1,15 @@
+/*
+ * Automatically generated by asn1_compiler. Do not edit
+ *
+ * ASN.1 parser for x509_akid
+ */
+#include <linux/asn1_decoder.h>
+
+extern const struct asn1_decoder x509_akid_decoder;
+
+extern int x509_akid_note_kid(void *, size_t, unsigned char, const void *, size_t);
+extern int x509_akid_note_name(void *, size_t, unsigned char, const void *, size_t);
+extern int x509_akid_note_serial(void *, size_t, unsigned char, const void *, size_t);
+extern int x509_extract_name_segment(void *, size_t, unsigned char, const void *, size_t);
+extern int x509_note_OID(void *, size_t, unsigned char, const void *, size_t);
+
diff --git a/copy-list b/copy-list
index 0bd232f4..d36caea3 100644
--- a/copy-list
+++ b/copy-list
@@ -61,6 +61,19 @@ include/net/codel_qdisc.h
include/net/fq.h
include/net/fq_impl.h
+# signature verification code
+include/linux/asn1.h
+include/linux/asn1_ber_bytecode.h
+include/linux/oid_registry.h
+lib/build_OID_registry -> compat/build_OID_registry
+crypto/asymmetric_keys/pkcs7_parser.c -> compat/verification/pkcs7_parser.c
+crypto/asymmetric_keys/pkcs7_parser.h -> compat/verification/pkcs7_parser.h
+crypto/asymmetric_keys/pkcs7_trust.c -> compat/verification/pkcs7_trust.c
+crypto/asymmetric_keys/pkcs7_verify.c -> compat/verification/pkcs7_verify.c
+crypto/asymmetric_keys/x509_cert_parser.c -> compat/verification/x509_cert_parser.c
+crypto/asymmetric_keys/x509_parser.h -> compat/verification/x509_parser.h
+crypto/asymmetric_keys/x509_public_key.c -> compat/verification/x509_public_key.c
+
net/Makefile
net/Kconfig
net/wireless/
diff --git a/patches/verify.patch b/patches/verify.patch
new file mode 100644
index 00000000..dbb5600e
--- /dev/null
+++ b/patches/verify.patch
@@ -0,0 +1,86 @@
+--- a/compat/verification/pkcs7_trust.c
++++ b/compat/verification/pkcs7_trust.c
+@@ -115,7 +115,7 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
+ return -ENOKEY;
+
+ matched:
+- ret = verify_signature(key, sig);
++ ret = public_key_verify_signature(key->public_key, sig);
+ key_put(key);
+ if (ret < 0) {
+ if (ret == -ENOMEM)
+--- a/compat/verification/x509_public_key.c
++++ b/compat/verification/x509_public_key.c
+@@ -13,11 +13,8 @@
+ #include <linux/module.h>
+ #include <linux/kernel.h>
+ #include <linux/slab.h>
+-#include <keys/asymmetric-subtype.h>
+-#include <keys/asymmetric-parser.h>
+ #include <keys/system_keyring.h>
+ #include <crypto/hash.h>
+-#include "asymmetric_keys.h"
+ #include "x509_parser.h"
+
+ /*
+@@ -159,6 +156,7 @@ not_self_signed:
+ return 0;
+ }
+
++#if 0
+ /*
+ * Attempt to parse a data blob for a key as an X509 certificate.
+ */
+@@ -276,3 +274,4 @@ module_exit(x509_key_exit);
+
+ MODULE_DESCRIPTION("X.509 certificate parser");
+ MODULE_LICENSE("GPL");
++#endif
+--- a/include/crypto/pkcs7.h
++++ b/include/crypto/pkcs7.h
+@@ -2,5 +2,10 @@
+ #ifndef CPTCFG_BPAUTO_PKCS7
+ #include_next <crypto/pkcs7.h>
+ #else
++#define pkcs7_verify LINUX_BACKPORT(pkcs7_verify)
++#define pkcs7_get_content_data LINUX_BACKPORT(pkcs7_get_content_data)
++#define pkcs7_parse_message LINUX_BACKPORT(pkcs7_parse_message)
++#define pkcs7_free_message LINUX_BACKPORT(pkcs7_free_message)
++#define pkcs7_validate_trust LINUX_BACKPORT(pkcs7_validate_trust)
+ #include <crypto/backport-pkcs7.h>
+ #endif /* CPTCFG_BPAUTO_PKCS7 */
+--- a/compat/verification/x509_parser.h
++++ b/compat/verification/x509_parser.h
+@@ -13,6 +13,10 @@
+ #include <crypto/public_key.h>
+ #include <keys/asymmetric-type.h>
+
++#define x509_decode_time LINUX_BACKPORT(x509_decode_time)
++#define x509_cert_parse LINUX_BACKPORT(x509_cert_parse)
++#define x509_free_certificate LINUX_BACKPORT(x509_free_certificate)
++
+ struct x509_certificate {
+ struct x509_certificate *next;
+ struct x509_certificate *signer; /* Certificate that signed this one */
+--- a/net/wireless/Makefile
++++ b/net/wireless/Makefile
+@@ -22,7 +22,7 @@ ifneq ($(CPTCFG_CFG80211_EXTRA_REGDB_KEYDIR),)
+ cfg80211-y += extra-certs.o
+ endif
+
+-$(obj)/shipped-certs.c: $(wildcard $(srctree)/$(src)/certs/*.x509)
++$(obj)/shipped-certs.c: $(wildcard $(src)/certs/*.x509)
+ @echo " GEN $@"
+ @echo '#include "reg.h"' > $@
+ @echo 'const u8 shipped_regdb_certs[] = {' >> $@
+--- a/compat/verification/pkcs7_verify.c
++++ b/compat/verification/pkcs7_verify.c
+@@ -150,7 +150,7 @@
+ pr_devel("Sig %u: Found cert serial match X.509[%u]\n",
+ sinfo->index, certix);
+
+- if (x509->pub->pkey_algo != sinfo->sig->pkey_algo) {
++ if (strcmp(x509->pub->pkey_algo, sinfo->sig->pkey_algo)) {
+ pr_warn("Sig %u: X.509 algo and PKCS#7 sig algo don't match\n",
+ sinfo->index);
+ continue;