From ea6511d3492355d88cc23afd1cb58f076219de44 Mon Sep 17 00:00:00 2001 From: Jaromil Date: Mon, 20 Jan 2025 22:55:36 +0100 Subject: [PATCH 01/14] feat: add up to date x509 milagro api from miracl/core --- build/init.mk | 3 +- lib/milagro-crypto-c/include/x509.h | 153 ++- lib/milagro-crypto-c/src/x509.c | 1615 ++++++++++++++------------- 3 files changed, 970 insertions(+), 801 deletions(-) diff --git a/build/init.mk b/build/init.mk index 709fbfbe7..d8802bc01 100644 --- a/build/init.mk +++ b/build/init.mk @@ -42,6 +42,7 @@ ldadd += ${milib}/libamcl_curve_${ecp_curve}.a ldadd += ${milib}/libamcl_pairing_${ecp_curve}.a ldadd += ${milib}/libamcl_curve_${ecdh_curve}.a ldadd += ${milib}/libamcl_rsa_2048.a ${milib}/libamcl_rsa_4096.a +ldadd += ${milib}/libamcl_x509.a ldadd += ${milib}/libamcl_core.a ldadd += ${pwd}/lib/pqclean/libqpz.a ldadd += ${pwd}/lib/ed25519-donna/libed25519.a @@ -80,7 +81,7 @@ rsa_bits := "2048,4096" # NUMS384E NUMS512W NUMS512E SECP256K1 BN254 BN254CX BLS381 BLS383 # BLS24 BLS48 FP256BN FP512BN BLS461 # see lib/milagro-crypto-c/cmake/AMCLParameters.cmake -milagro_cmake_flags += -DBUILD_SHARED_LIBS=OFF -DBUILD_PYTHON=OFF -DBUILD_DOXYGEN=OFF -DBUILD_DOCS=OFF -DBUILD_BENCHMARKS=OFF -DBUILD_EXAMPLES=OFF -DWORD_SIZE=32 -DBUILD_PAILLIER=OFF -DBUILD_X509=OFF -DBUILD_WCC=OFF -DBUILD_MPIN=OFF -DAMCL_CURVE=${ecdh_curve},${ecp_curve} -DAMCL_RSA=${rsa_bits} -DAMCL_PREFIX=AMCL_ -DCMAKE_SHARED_LIBRARY_LINK_FLAGS="" -DC99=1 -DPAIRING_FRIENDLY_BLS381='BLS' -DCOMBA=1 -DBUILD_TESTING=OFF +milagro_cmake_flags += -DBUILD_SHARED_LIBS=OFF -DBUILD_PYTHON=OFF -DBUILD_DOXYGEN=OFF -DBUILD_DOCS=OFF -DBUILD_BENCHMARKS=OFF -DBUILD_EXAMPLES=OFF -DWORD_SIZE=32 -DBUILD_PAILLIER=OFF -DBUILD_X509=ON -DBUILD_WCC=OFF -DBUILD_MPIN=OFF -DAMCL_CURVE=${ecdh_curve},${ecp_curve} -DAMCL_RSA=${rsa_bits} -DAMCL_PREFIX=AMCL_ -DCMAKE_SHARED_LIBRARY_LINK_FLAGS="" -DC99=1 -DPAIRING_FRIENDLY_BLS381='BLS' -DCOMBA=1 -DBUILD_TESTING=OFF #----------------- # quantum-proof diff --git a/lib/milagro-crypto-c/include/x509.h b/lib/milagro-crypto-c/include/x509.h index 2c4a7b942..81a96ab32 100644 --- a/lib/milagro-crypto-c/include/x509.h +++ b/lib/milagro-crypto-c/include/x509.h @@ -1,23 +1,23 @@ /* -Licensed to the Apache Software Foundation (ASF) under one -or more contributor license agreements. See the NOTICE file -distributed with this work for additional information -regarding copyright ownership. The ASF licenses this file -to you under the Apache License, Version 2.0 (the -"License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, -software distributed under the License is distributed on an -"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -KIND, either express or implied. See the License for the -specific language governing permissions and limitations -under the License. -*/ + * Copyright (c) 2012-2020 MIRACL UK Ltd. + * + * This file is part of MIRACL Core + * (see https://github.com/miracl/core). + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ -/* AMCL x509 header file */ +/* CORE x509 header file */ /** * @file x509.h @@ -29,6 +29,42 @@ under the License. #ifndef X509_H #define X509_H +// Supported Encryption Methods + +#define X509_ECC 1 /**< Uses Elliptic Curve Cryptography */ +#define X509_RSA 2 /**< Uses RSA Cryptography */ +#define X509_ECD 3 /**< Uses Ed25519 cryptography */ +#define X509_PQ 4 /**< Uses Post Quantum Cryptography */ + +// Supported Hash functions + +#define X509_H256 2 /**< Using SHA256 hashing */ +#define X509_H384 3 /**< Using SHA384 hashing */ +#define X509_H512 4 /**< Using SHA512 hashing */ +#define X509_SHAKE256 5 /**< Using SHA3-SHAKE256 hashing */ + +// Supported Curves + +#define USE_NIST256 0 /**< For the NIST 256-bit standard curve - WEIERSTRASS only */ +#define USE_ED25519 1 /**< Bernstein's Modulus 2^255-19 - EDWARDS */ +#define USE_ED448 4 /**< Goldilocks Modulus Ed448 - EDWARDS */ +#define USE_BRAINPOOL 2 /**< For Brainpool 256-bit curve - WEIERSTRASS only */ +#define USE_ANSSI 3 /**< For French 256-bit standard curve - WEIERSTRASS only */ +#define USE_NIST384 10 /**< For the NIST 384-bit standard curve - WEIERSTRASS only */ +#define USE_NIST521 12 /**< For the NIST 521-bit standard curve - WEIERSTRASS only */ + +extern octet X509_CN; /**< Country Name */ +extern octet X509_ON; /**< Organisation Name */ +extern octet X509_EN; /**< Email */ +extern octet X509_LN; /**< Local Name */ +extern octet X509_UN; /**< Unit Name */ +extern octet X509_MN; /**< My name */ +extern octet X509_SN; /**< State Name */ + +extern octet X509_AN; /**< Alternate Name */ +extern octet X509_KU; /**< Key Usage */ +extern octet X509_BC; /**< Basic Constraints */ + /** * @brief Public key type */ @@ -41,34 +77,62 @@ typedef struct /* X.509 functions */ + +/** @brief Extract private key + * + @param c an X.509 private key + @param pk the extracted private key - for RSA octet = p|q|dp|dq|c, for ECC octet = k + @return indicator of private key type (ECC or RSA) +*/ +extern pktype X509_extract_private_key(octet *c,octet *pk); + /** @brief Extract certificate signature * @param c an X.509 certificate @param s the extracted signature - @return 0 on failure, or indicator of signature type (ECC or RSA) + @return indicator of signature type (ECC or RSA) */ -extern pktype X509_extract_cert_sig(octet *c,octet *s); +extern pktype X509_extract_cert_sig(octet *c, octet *s); /** @brief * @param sc a signed certificate @param c the extracted certificate @return 0 on failure */ -extern int X509_extract_cert(octet *sc,octet *c); +extern int X509_extract_cert(octet *sc, octet *c); + + +/** @brief + * + @param c an X.509 certificate + @param ptr pointer to ASN.1 raw public key + @return length of raw public key +*/ +extern int X509_find_public_key(octet *c,int *ptr); + +/** @brief + * + @param c an ASN.1 encoded public key + @param key the extracted public key + @return indicator of public key type (ECC or RSA) +*/ +extern pktype X509_get_public_key(octet *c,octet *key); + /** @brief * @param c an X.509 certificate @param k the extracted key - @return 0 on failure, or indicator of public key type (ECC or RSA) + @return indicator of public key type (ECC or RSA) */ -extern pktype X509_extract_public_key(octet *c,octet *k); +extern pktype X509_extract_public_key(octet *c, octet *k); /** @brief * @param c an X.509 certificate + @param len length of issuer field @return 0 on failure, or pointer to issuer field in cert */ -extern int X509_find_issuer(octet *c); +extern int X509_find_issuer(octet *c,int *len); /** @brief * @param c an X.509 certificate @@ -78,9 +142,18 @@ extern int X509_find_validity(octet *c); /** @brief * @param c an X.509 certificate + @param len length of subject field @return 0 on failure, or pointer to subject field in cert */ -extern int X509_find_subject(octet *c); +extern int X509_find_subject(octet *c,int *len); + +/** @brief + * + @param c an X.509 certificate + @return true if self-signed, else false +*/ +extern int X509_self_signed(octet *c); + /** @brief * @param c an X.509 certificate @@ -89,21 +162,45 @@ extern int X509_find_subject(octet *c); @param f is pointer to the length of the property @return 0 on failure, or pointer to the property */ -extern int X509_find_entity_property(octet *c,octet *S,int s,int *f); +extern int X509_find_entity_property(octet *c, octet *S, int s, int *f); /** @brief * @param c an X.509 certificate @param s is a pointer to the start of the validity field @return 0 on failure, or pointer to the start date */ -extern int X509_find_start_date(octet *c,int s); +extern int X509_find_start_date(octet *c, int s); /** @brief * @param c an X.509 certificate @param s is a pointer to the start of the validity field @return 0 on failure, or pointer to the expiry date */ -extern int X509_find_expiry_date(octet *c,int s); +extern int X509_find_expiry_date(octet *c, int s); +/** @brief + * + @param c an X.509 certificate + @return 0 on failure (or no extensions), or pointer to extensions field in cert +*/ +extern int X509_find_extensions(octet *c); +/** @brief + * + @param c an X.509 certificate + @param S is OID of particular extension we are looking for + @param s is a pointer to the section of interest in the cert + @param f is pointer to the length of the extension + @return 0 on failure, or pointer to the extension +*/ +extern int X509_find_extension(octet *c, octet *S, int s, int *f); + +/** @brief + * + @param c an X.509 certificate + @param s is a pointer to certificate extension SubjectAltNames + @param name is a URL + @return 0 on failure, 1 if URL is in list of alt names +*/ +extern int X509_find_alt_name(octet *c,int s,char *name); #endif diff --git a/lib/milagro-crypto-c/src/x509.c b/lib/milagro-crypto-c/src/x509.c index 84f6c5328..7ea7533dd 100644 --- a/lib/milagro-crypto-c/src/x509.c +++ b/lib/milagro-crypto-c/src/x509.c @@ -1,32 +1,27 @@ /* -Licensed to the Apache Software Foundation (ASF) under one -or more contributor license agreements. See the NOTICE file -distributed with this work for additional information -regarding copyright ownership. The ASF licenses this file -to you under the Apache License, Version 2.0 (the -"License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, -software distributed under the License is distributed on an -"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -KIND, either express or implied. See the License for the -specific language governing permissions and limitations -under the License. -*/ - -/* AMCL X.509 Functions */ - -// To run test program, define HAS_MAIN -// gcc -std=c99 x509.c amcl.a -o x509.exe - -//#define HAS_MAIN + * Copyright (c) 2012-2020 MIRACL UK Ltd. + * + * This file is part of MIRACL Core + * (see https://github.com/miracl/core). + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* CORE X.509 Functions */ #include -#include "amcl.h" // for octet support only -#include "x509.h" +#include // for octet support only +#include // ASN.1 tags @@ -38,137 +33,144 @@ under the License. #define ZER 0x00 #define UTF 0x0C #define UTC 0x17 +#define GTM 0x18 #define LOG 0x01 #define BIT 0x03 #define OCT 0x04 #define STR 0x13 #define SET 0x31 #define IA5 0x16 - -// Supported Encryption Methods - -#define ECC 1 -#define RSA 2 - -// Supported Hash functions - -#define H256 2 -#define H384 3 -#define H512 4 - -// Supported Curves - -#define NIST256 0 /**< For the NIST 256-bit standard curve - WEIERSTRASS only */ -#define C25519 1 /**< Bernstein's Modulus 2^255-19 - EDWARDS or MONTGOMERY only */ -#define BRAINPOOL 2 /**< For Brainpool 256-bit curve - WEIERSTRASS only */ -#define ANSSI 3 /**< For French 256-bit standard curve - WEIERSTRASS only */ -#define NIST384 10 /**< For the NIST 384-bit standard curve - WEIERSTRASS only */ -#define NIST521 12 /**< For the NIST 521-bit standard curve - WEIERSTRASS only */ - +#define EXT 0xA3 +#define DNS 0x82 // Define some OIDs // Elliptic Curve with SHA256 -static unsigned char eccsha256[8]= {0x2a,0x86,0x48,0xce,0x3d,0x04,0x03,0x02}; -static octet ECCSHA256= {8,sizeof(eccsha256),(char *)eccsha256}; +static unsigned char eccsha256[8] = {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02}; +static octet ECCSHA256 = {8, sizeof(eccsha256), (char *)eccsha256}; // Elliptic Curve with SHA384 -static unsigned char eccsha384[8]= {0x2a,0x86,0x48,0xce,0x3d,0x04,0x03,0x03}; -static octet ECCSHA384= {8,sizeof(eccsha384),(char *)eccsha384}; +static unsigned char eccsha384[8] = {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03}; +static octet ECCSHA384 = {8, sizeof(eccsha384), (char *)eccsha384}; // Elliptic Curve with SHA512 -static unsigned char eccsha512[8]= {0x2a,0x86,0x48,0xce,0x3d,0x04,0x03,0x04}; -static octet ECCSHA512= {8,sizeof(eccsha512),(char *)eccsha512}; +static unsigned char eccsha512[8] = {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x04}; +static octet ECCSHA512 = {8, sizeof(eccsha512), (char *)eccsha512}; // EC Public Key -static unsigned char ecpk[7]= {0x2a,0x86,0x48,0xce,0x3d,0x02,0x01}; -static octet ECPK= {7,sizeof(ecpk),(char *)ecpk}; +static unsigned char ecpk[7] = {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01}; +static octet ECPK = {7, sizeof(ecpk), (char *)ecpk}; + +// ED25519 Public Key - Elliptic curve EdDSA (Ed25519) Signature +static unsigned char edpk25519[3] = {0x2B, 0x65, 0x70}; +static octet EDPK25519 = {3, sizeof(edpk25519),(char *)edpk25519}; + +// ED448 Public Key - Elliptic curve EdDSA (Ed448) Signature +static unsigned char edpk448[3] = {0x2B, 0x65, 0x71}; +static octet EDPK448 = {3, sizeof(edpk448),(char *)edpk448}; // C25519 curve -static unsigned char prime25519[9]= {0x2B,0x06,0x01,0x04,0x01,0xDA,0x47,0x0F,0x01}; /*****/ -static octet PRIME25519= {9,sizeof(prime25519),(char *)prime25519}; +static unsigned char prime25519[9] = {0x2B, 0x06, 0x01, 0x04, 0x01, 0xDA, 0x47, 0x0F, 0x01}; /*****/ +static octet PRIME25519 = {9, sizeof(prime25519), (char *)prime25519}; // NIST256 curve -static unsigned char prime256v1[8]= {0x2a,0x86,0x48,0xce,0x3d,0x03,0x01,0x07}; -static octet PRIME256V1= {8,sizeof(prime256v1),(char *)prime256v1}; +static unsigned char prime256v1[8] = {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07}; +static octet PRIME256V1 = {8, sizeof(prime256v1), (char *)prime256v1}; // NIST384 curve -static unsigned char secp384r1[5]= {0x2B,0x81,0x04,0x00,0x22}; -static octet SECP384R1= {5,sizeof(secp384r1),(char *)secp384r1}; +static unsigned char secp384r1[5] = {0x2B, 0x81, 0x04, 0x00, 0x22}; +static octet SECP384R1 = {5, sizeof(secp384r1), (char *)secp384r1}; // NIST521 curve -static unsigned char secp521r1[5]= {0x2B,0x81,0x04,0x00,0x23}; -static octet SECP521R1= {5,sizeof(secp521r1),(char *)secp521r1}; +static unsigned char secp521r1[5] = {0x2B, 0x81, 0x04, 0x00, 0x23}; +static octet SECP521R1 = {5, sizeof(secp521r1), (char *)secp521r1}; // RSA Public Key -static unsigned char rsapk[9]= {0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01}; -static octet RSAPK= {9,sizeof(rsapk),(char *)rsapk}; +static unsigned char rsapk[9] = {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01}; +static octet RSAPK = {9, sizeof(rsapk), (char *)rsapk}; // RSA with SHA256 -static unsigned char rsasha256[9]= {0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x0b}; -static octet RSASHA256= {9,sizeof(rsasha256),(char *)rsasha256}; +static unsigned char rsasha256[9] = {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b}; +static octet RSASHA256 = {9, sizeof(rsasha256), (char *)rsasha256}; // RSA with SHA384 -static unsigned char rsasha384[9]= {0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x0c}; -static octet RSASHA384= {9,sizeof(rsasha384),(char *)rsasha384}; +static unsigned char rsasha384[9] = {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0c}; +static octet RSASHA384 = {9, sizeof(rsasha384), (char *)rsasha384}; // RSA with SHA512 -static unsigned char rsasha512[9]= {0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x0d}; -static octet RSASHA512= {9,sizeof(rsasha512),(char *)rsasha512}; +static unsigned char rsasha512[9] = {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0d}; +static octet RSASHA512 = {9, sizeof(rsasha512), (char *)rsasha512}; + +// DILITHIUM3 +static unsigned char dilithium3[11] = {0x2b, 0x06, 0x01, 0x04, 0x01, 0x02, 0x82, 0x0B, 0x07, 0x06, 0x05}; +static octet DILITHIUM3 = {11, sizeof(dilithium3), (char *)dilithium3}; + -#ifdef HAS_MAIN +// Cert details // countryName -static unsigned char cn[3]= {0x55,0x04,0x06}; -static octet CN= {3,sizeof(cn),(char *)cn}; +static unsigned char cn[3] = {0x55, 0x04, 0x06}; +octet X509_CN = {3, sizeof(cn), (char *)cn}; // stateName -// static char sn[3]= {0x55,0x04,0x08}; -// static octet SN= {3,sizeof(sn),sn}; +static char sn[3]= {0x55,0x04,0x08}; +octet X509_SN= {3,sizeof(sn),sn}; // localName -// static char ln[3]= {0x55,0x04,0x07}; -// static octet LN= {3,sizeof(ln),ln}; +static char ln[3]= {0x55,0x04,0x07}; +octet X509_LN= {3,sizeof(ln),ln}; // orgName -static unsigned char on[3]= {0x55,0x04,0x0A}; -static octet ON= {3,sizeof(on),(char *)on}; +static unsigned char on[3] = {0x55, 0x04, 0x0A}; +octet X509_ON = {3, sizeof(on), (char *)on}; // unitName -// static char un[3]= {0x55,0x04,0x0B}; -// static octet UN= {3,sizeof(un),un}; +static char un[3]= {0x55,0x04,0x0B}; +octet X509_UN= {3,sizeof(un),un}; // myName -// static char mn[3]= {0x55,0x04,0x03}; -// static octet MN= {3,sizeof(mn),mn}; +static char mn[3]= {0x55,0x04,0x03}; +octet X509_MN= {3,sizeof(mn),mn}; // emailName -static unsigned char en[9]= {0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x09,0x01}; -static octet EN= {9,sizeof(en),(char *)en}; -#endif // HAS_MAIN +static unsigned char en[9] = {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01}; +octet X509_EN = {9, sizeof(en), (char *)en}; + +// Extensions +// Alt Name +static char an[3]={0x55,0x1D,0x11}; +octet X509_AN = {3, sizeof(an),an}; + +// Key Usage +static char ku[3]={0x55,0x1d,0x0f}; +octet X509_KU = {3,sizeof(ku),ku}; + +// Basic Constraints +static char bc[3]={0x55,0x1d,0x13}; +octet X509_BC = {3,sizeof(bc),bc}; /* Check expected TAG and return ASN.1 field length. If tag=0 skip check. */ -static int getalen(int tag,char *b,int j) +static int getalen(int tag, char *b, int j) { int len; - if (tag!=0 && (unsigned char)b[j]!=tag) return -1; // not a valid tag + if (tag != 0 && (unsigned char)b[j] != tag) return -1; // not a valid tag j++; - if ((unsigned char)b[j]==0x81) + if ((unsigned char)b[j] == 0x81) { j++; - len=(unsigned char)b[j]; + len = (unsigned char)b[j]; } - else if ((unsigned char)b[j]==0x82) + else if ((unsigned char)b[j] == 0x82) { j++; - len=256*b[j++]; - len+=(unsigned char)b[j]; + len = 256 * b[j++]; + len += (unsigned char)b[j]; } else { - len=(unsigned char)b[j]; - if (len>127) return -1; + len = (unsigned char)b[j]; + if (len > 127) return -1; } return len; } @@ -176,391 +178,724 @@ static int getalen(int tag,char *b,int j) /* jump over length field */ static int skip(int len) { - if (len<128) return 2; - if (len>=128 && len<256) return 3; + if (len < 128) return 2; + if (len < 256) return 3; return 4; } /* round length up to nearest 8-byte length */ static int bround(int len) { - if (len%8==0) return len; - return len+(8-len%8); + if (len % 8 == 0) return len; + return len + (8 - len % 8); + +} + +// Input private key in PKCS#8 format +// e.g. openssl req -x509 -nodes -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 +// e.g. openssl req -x509 -nodes -days 3650 -newkey ec:<(openssl ecparam -name prime256v1) -keyout key.pem -out ecdsacert.pem +// extract private key from uncompressed key.pem into octet +// For RSA octet = p|q|dp|dq|c where pk->len is multiple of 5 +// For ECC octet = k +pktype X509_extract_private_key(octet *c,octet *pk) +{ + int i, j, k, fin, len, rlen, flen, tlen, sj, ex; + char soid[12]; + octet SOID = {0, sizeof(soid), soid}; + pktype ret; + + ret.type = 0; + ret.hash = 0; + j=0; + + len = getalen(SEQ, c->val, j); // Check for expected SEQ clause, and get length + if (len < 0) return ret; // if not a SEQ clause, there is a problem, exit + j += skip(len); // skip over length to clause contents. Add len to skip clause + + if (len + j != c->len) return ret; + + len = getalen(INT, c->val, j); + if (len < 0) return ret; + j += skip(len) + len; // jump over serial number clause (if there is one) + + len = getalen(SEQ, c->val, j); + if (len < 0) return ret; + j += skip(len); + +// extract OID + len = getalen(OID, c->val, j); + if (len < 0) return ret; + j += skip(len); + + fin = j + len; + if (len>SOID.max) return ret; + SOID.len = len; + for (i = 0; j < fin; j++) + SOID.val[i++] = c->val[j]; + j=fin; + + if (OCT_comp(&EDPK25519, &SOID)) + { // Its an Ed25519 key + len = getalen(OCT, c->val, j); + if (len < 0) return ret; + j += skip(len); + len = getalen(OCT, c->val, j); + if (len < 0) return ret; + j += skip(len); + rlen=32; + if (rlen>pk->max) return ret; + pk->len=rlen; + for (i=0;ival[i]=0; + for (i=rlen-len;ival[i]=c->val[j++]; + ret.type = X509_ECD; + ret.curve = USE_ED25519; + } + if (OCT_comp(&EDPK448, &SOID)) + { // Its an Ed25519 key + len = getalen(OCT, c->val, j); + if (len < 0) return ret; + j += skip(len); + len = getalen(OCT, c->val, j); + if (len < 0) return ret; + j += skip(len); + rlen=57; + if (rlen>pk->max) return ret; + pk->len=rlen; + for (i=0;ival[i]=0; + for (i=rlen-len;ival[i]=c->val[j++]; + ret.type = X509_ECD; + ret.curve = USE_ED448; + } + if (OCT_comp(&DILITHIUM3, &SOID)) + { // Its a DILITHIUM3 key + len = getalen(OCT, c->val, j); + if (len < 0) return ret; + j += skip(len); + len = getalen(OCT, c->val, j); + if (len < 0) return ret; + j += skip(len); + tlen=len; + if (tlen>pk->max) + tlen=pk->max; + for (i=0;ival[i]=c->val[j++]; + pk->len=tlen; + ret.type=X509_PQ; + ret.curve=8*tlen; + } + if (OCT_comp(&ECPK, &SOID)) + { // Its an ECC key + len = getalen(OID, c->val, j); + if (len < 0) return ret; + j += skip(len); + + fin = j + len; + if (len>SOID.max) return ret; + SOID.len = len; + for (i = 0; j < fin; j++) + SOID.val[i++] = c->val[j]; + j=fin; + + len = getalen(OCT, c->val, j); + if (len < 0) return ret; + j += skip(len); + + len = getalen(SEQ, c->val, j); + if (len < 0) return ret; + j += skip(len); + + len = getalen(INT, c->val, j); + if (len < 0) return ret; + j += skip(len) + len; // jump over version + + len = getalen(OCT, c->val, j); + if (len < 0) return ret; + j += skip(len); + + ret.type = X509_ECC; + if (OCT_comp(&PRIME256V1, &SOID)) { + ret.curve = USE_NIST256; + rlen=32; + } + if (OCT_comp(&SECP384R1, &SOID)) { + ret.curve = USE_NIST384; + rlen=48; + } + if (OCT_comp(&SECP521R1, &SOID)) { + rlen=66; + ret.curve = USE_NIST521; + } + if (rlen>pk->max) + { + ret.curve=0; + return ret; + } + pk->len=rlen; + for (i=0;ival[i]=0; + for (i=rlen-len;ival[i]=c->val[j++]; + + } + if (OCT_comp(&RSAPK, &SOID)) + { // Its an RSA key + len = getalen(NUL, c->val, j); + if (len<0) return ret; + j += skip(len); + + len = getalen(OCT, c->val, j); + if (len < 0) return ret; + j += skip(len); + + len = getalen(SEQ, c->val, j); + if (len < 0) return ret; + j += skip(len); + + len = getalen(INT, c->val, j); + if (len < 0) return ret; + j += skip(len) + len; // jump over version + len = getalen(INT, c->val, j); + if (len < 0) return ret; + j += skip(len) + len; // jump over n + + len = getalen(INT, c->val, j); + if (len < 0) return ret; + j += skip(len) + len; // jump over e + + len = getalen(INT, c->val, j); + if (len < 0) return ret; + j += skip(len) + len; // jump over d + + + len = getalen(INT, c->val, j); + if (len < 0) return ret; + j += skip(len); // get p + + if (c->val[j] == 0) + { // skip leading zero + j++; + len--; + } + rlen=bround(len); + if (5*rlen>pk->max) + return ret; + + + for (i=0;ival[i]=0; + + for (i=rlen-len;ival[i]=c->val[j++]; + + flen=rlen; // should be same length for all + for (k=1;k<5;k++) + { + len = getalen(INT,c->val,j); + if (len<0) return ret; + j += skip(len); // get q,dp,dq,c + if (c->val[j] == 0) + { // skip leading zero + j++; + len--; + } + rlen=bround(len); + if (rlen!=flen) return ret; + for (i=0;ival[i]=0; + for (i=rlen-len;ival[k*flen+i]=c->val[j++]; + } + pk->len=5*flen; + ret.type = X509_RSA; + ret.curve = 16 * flen; + } + return ret; } -// Input signed cert as octet, and extract signature -// Return 0 for failure, ECC for Elliptic Curve signature, RSA for RSA signature +// Input signed cert as octet, and extract signature +// Return 0 for failure, ECC for Elliptic Curve signature, RSA for RSA signature // Note that signature type is not provided here - its the type of the public key that // is used to verify it that matters, and which determines for example the curve to be used! -pktype X509_extract_cert_sig(octet *sc,octet *sig) +pktype X509_extract_cert_sig(octet *sc, octet *sig) { - int i,j,k,fin,len,rlen,sj,ex; - char soid[9]; - octet SOID= {0,sizeof(soid),soid}; + int i, j, k, fin, len, rlen, sj, ex; + char soid[12]; + octet SOID = {0, sizeof(soid), soid}; pktype ret; - ret.type=0; - ret.hash=0; + ret.type = 0; + ret.hash = 0; - j=0; + j = 0; - len=getalen(SEQ,sc->val,j); // Check for expected SEQ clause, and get length - if (len<0) return ret; // if not a SEQ clause, there is a problem, exit - j+=skip(len); // skip over length to clause contents. Add len to skip clause + len = getalen(SEQ, sc->val, j); // Check for expected SEQ clause, and get length + if (len < 0) return ret; // if not a SEQ clause, there is a problem, exit + j += skip(len); // skip over length to clause contents. Add len to skip clause - if (len+j!=sc->len) return ret; + if (len + j != sc->len) return ret; - len=getalen(SEQ,sc->val,j); - if (len<0) return ret; - j+=skip(len)+len; // jump over cert to signature OID + len = getalen(SEQ, sc->val, j); + if (len < 0) return ret; + j += skip(len) + len; // jump over cert to signature OID - len=getalen(SEQ,sc->val,j); - if (len<0) return ret; - j+=skip(len); + len = getalen(SEQ, sc->val, j); + if (len < 0) return ret; + j += skip(len); - sj=j+len; // Needed to jump over signature OID + sj = j + len; // Needed to jump over signature OID // dive in to extract OID - len=getalen(OID,sc->val,j); - if (len<0) return ret; - j+=skip(len); + len = getalen(OID, sc->val, j); + if (len < 0) return ret; + j += skip(len); - fin=j+len; - SOID.len=len; - for (i=0; jval[j]; + fin = j + len; + if (len>SOID.max) return ret; + SOID.len = len; + for (i = 0; j < fin; j++) + SOID.val[i++] = sc->val[j]; // check OID here.. - - if (OCT_comp(&ECCSHA256,&SOID)) + if (OCT_comp(&EDPK25519, &SOID)) { - ret.type=ECC; - ret.hash=H256; + ret.type = X509_ECD; + ret.hash = X509_H512; } - if (OCT_comp(&ECCSHA384,&SOID)) + if (OCT_comp(&EDPK448, &SOID)) { - ret.type=ECC; - ret.hash=H384; + ret.type = X509_ECD; + ret.hash = X509_SHAKE256; } - if (OCT_comp(&ECCSHA512,&SOID)) + if (OCT_comp(&ECCSHA256, &SOID)) { - ret.type=ECC; - ret.hash=H512; + ret.type = X509_ECC; + ret.hash = X509_H256; } - if (OCT_comp(&RSASHA256,&SOID)) + if (OCT_comp(&ECCSHA384, &SOID)) { - ret.type=RSA; - ret.hash=H256; + ret.type = X509_ECC; + ret.hash = X509_H384; } - if (OCT_comp(&RSASHA384,&SOID)) + if (OCT_comp(&ECCSHA512, &SOID)) { - ret.type=RSA; - ret.hash=H384; + ret.type = X509_ECC; + ret.hash = X509_H512; } - if (OCT_comp(&RSASHA512,&SOID)) + if (OCT_comp(&RSASHA256, &SOID)) { - ret.type=RSA; - ret.hash=H512; + ret.type = X509_RSA; + ret.hash = X509_H256; } + if (OCT_comp(&RSASHA384, &SOID)) + { + ret.type = X509_RSA; + ret.hash = X509_H384; + } + if (OCT_comp(&RSASHA512, &SOID)) + { + ret.type = X509_RSA; + ret.hash = X509_H512; + } + if (OCT_comp(&DILITHIUM3, &SOID)) + { + ret.type = X509_PQ; + ret.hash = 0; // hash type is implicit + } + if (ret.type == 0) return ret; // unsupported type - if (ret.type==0) return ret; // unsupported type - - j=sj; // jump out to signature + j = sj; // jump out to signature - len=getalen(BIT,sc->val,j); - if (len<0) + len = getalen(BIT, sc->val, j); + if (len < 0) { - ret.type=0; + ret.type = 0; return ret; } - j+=skip(len); + j += skip(len); j++; len--; // skip bit shift (hopefully 0!) - if (ret.type==ECC) + if (ret.type==X509_ECD) { - // signature in the form (r,s) - len=getalen(SEQ,sc->val,j); - if (len<0) + if (len>sig->max) { ret.type=0; return ret; } - j+=skip(len); + sig->len = len; + i = 0; + + fin = j + len; + for (; j < fin; j++) + sig->val[i++] = sc->val[j]; + + if (ret.hash == X509_H512) ret.curve = USE_ED25519; + if (ret.hash == X509_SHAKE256) ret.curve = USE_ED448; + } + + if (ret.type == X509_ECC) + { + // signature in the form (r,s) + len = getalen(SEQ, sc->val, j); + if (len < 0) + { + ret.type = 0; + return ret; + } + j += skip(len); // pick up r part of signature - len=getalen(INT,sc->val,j); - if (len<0) + len = getalen(INT, sc->val, j); + if (len < 0) { - ret.type=0; + ret.type = 0; return ret; } - j+=skip(len); + j += skip(len); - if (sc->val[j]==0) + if (sc->val[j] == 0) { // skip leading zero j++; len--; } - rlen=bround(len); + rlen = bround(len); - ex=rlen-len; - sig->len=2*rlen; + ex = rlen - len; + if (2*rlen>sig->max) + { + ret.type=0; + return ret; + } + sig->len = 2 * rlen; - i=0; - for (k=0; kval[i++]=0; + i = 0; + for (k = 0; k < ex; k++) + sig->val[i++] = 0; - fin=j+len; - for (; jval[i++]= sc->val[j]; + fin = j + len; + for (; j < fin; j++) + sig->val[i++] = sc->val[j]; // pick up s part of signature - len=getalen(INT,sc->val,j); - if (len<0) + len = getalen(INT, sc->val, j); + if (len < 0) { - ret.type=0; + ret.type = 0; return ret; } - j+=skip(len); + j += skip(len); - if (sc->val[j]==0) + if (sc->val[j] == 0) { // skip leading zeros j++; len--; } - rlen=bround(len); - ex=rlen-len; - for (k=0; kval[i++]=0; - - fin=j+len; - for (; jval[i++]= sc->val[j]; - + rlen = bround(len); + ex = rlen - len; + for (k = 0; k < ex; k++) + sig->val[i++] = 0; + + fin = j + len; + for (; j < fin; j++) + sig->val[i++] = sc->val[j]; + + if (ret.hash == X509_H256) ret.curve = USE_NIST256; + if (ret.hash == X509_H384) ret.curve = USE_NIST384; + if (ret.hash == X509_H512) ret.curve = USE_NIST521; } - if (ret.type==RSA) + if (ret.type == X509_RSA) { - rlen=bround(len); - ex=rlen-len; + rlen = bround(len); + ex = rlen - len; - sig->len=rlen; - i=0; - for (k=0; kval[i++]=0; + if (rlen>sig->max) + { + ret.type=0; + return ret; + } + sig->len = rlen; + i = 0; + for (k = 0; k < ex; k++) + sig->val[i++] = 0; - fin=j+len; - for (; jval[i++]= sc->val[j]; + fin = j + len; + for (; j < fin; j++) + sig->val[i++] = sc->val[j]; + ret.curve = 8*rlen; + } + if (ret.type == X509_PQ) + { + if (len>sig->max) + { + ret.type=0; + return ret; + } + sig->len = len; + fin = j + len; + for (i=0; j < fin; j++) + sig->val[i++] = sc->val[j]; + ret.curve = 8*len; } - if (ret.hash==H256) ret.curve=NIST256; - if (ret.hash==H384) ret.curve=NIST384; - if (ret.hash==H512) ret.curve=NIST521; - return ret; } // Extract certificate from signed cert -int X509_extract_cert(octet *sc,octet *cert) +int X509_extract_cert(octet *sc, octet *cert) { - int i,j,fin,len,k; + int i, j, fin, len, k; - j=0; - len=getalen(SEQ,sc->val,j); + j = 0; + len = getalen(SEQ, sc->val, j); - if (len<0) return 0; - j+=skip(len); + if (len < 0) return 0; + j += skip(len); - k=j; + k = j; - len=getalen(SEQ,sc->val,j); - if (len<0) return 0; - j+=skip(len); + len = getalen(SEQ, sc->val, j); + if (len < 0) return 0; + j += skip(len); - fin=j+len; - cert->len=fin-k; - for (i=k; ival[i-k]=sc->val[i]; + fin = j + len; + if (fin-k>cert->max) return 0; + cert->len = fin - k; + for (i = k; i < fin; i++) cert->val[i - k] = sc->val[i]; return 1; } -// Extract Public Key from inside Certificate -pktype X509_extract_public_key(octet *c,octet *key) +// find index to start of ASN.1 raw public key, and return its length +int X509_find_public_key(octet *c,int *ptr) { - int i,j,fin,len,sj; - char koid[12]; /*****/ - octet KOID= {0,sizeof(koid),koid}; - pktype ret; + int i, j, k, fin, len, sj; - ret.type=ret.hash=0; - ret.curve=-1; + j = 0; - j=0; + len = getalen(SEQ, c->val, j); + if (len < 0) return 0; + j += skip(len); - len=getalen(SEQ,c->val,j); - if (len<0) return ret; - j+=skip(len); + if (len + j != c->len) return 0; - if (len+j!=c->len) return ret; + len = getalen(ANY, c->val, j); + if (len < 0) return 0; + j += skip(len) + len; //jump over version clause - len=getalen(0,c->val,j); - if (len<0) return ret; - j+=skip(len)+len; //jump over version clause + len = getalen(INT, c->val, j); - len=getalen(INT,c->val,j); + if (len > 0) j += skip(len) + len; // jump over serial number clause (if there is one) - if (len>0) j+=skip(len)+len; // jump over serial number clause (if there is one) + len = getalen(SEQ, c->val, j); + if (len < 0) return 0; + j += skip(len) + len; // jump over signature algorithm - len=getalen(SEQ,c->val,j); - if (len<0) return ret; - j+=skip(len)+len; // jump over signature algorithm + len = getalen(SEQ, c->val, j); + if (len < 0) return 0; + j += skip(len) + len; // skip issuer - len=getalen(SEQ,c->val,j); - if (len<0) return ret; - j+=skip(len)+len; // skip issuer + len = getalen(SEQ, c->val, j); + if (len < 0) return 0; + j += skip(len) + len; // skip validity - len=getalen(SEQ,c->val,j); - if (len<0) return ret; - j+=skip(len)+len; // skip validity + len = getalen(SEQ, c->val, j); + if (len < 0) return 0; + j += skip(len) + len; // skip subject - len=getalen(SEQ,c->val,j); - if (len<0) return ret; - j+=skip(len)+len; // skip subject + k=j; + len = getalen(SEQ, c->val, j); // look ahead to determine length + if (len < 0) return 0; + j += skip(len); // - len=getalen(SEQ,c->val,j); - if (len<0) return ret; - j+=skip(len); // + fin=j+len; + *ptr=k; + return fin-k; +} - len=getalen(SEQ,c->val,j); - if (len<0) return ret; - j+=skip(len); +// get Public Key details from ASN.1 description +pktype X509_get_public_key(octet *c,octet *key) +{ + int i, j, fin, len, sj, ptr; + char koid[16]; /*****/ + octet KOID = {0, sizeof(koid), koid}; + pktype ret; + + ret.type = ret.hash = 0; + ret.curve = -1; + + j=0; + + len = getalen(SEQ, c->val, j); + if (len < 0) return ret; + j += skip(len); // + + len = getalen(SEQ, c->val, j); + if (len < 0) return ret; + j += skip(len); // ** Maybe dive in and check Public Key OIDs here? // ecpublicKey & prime256v1, secp384r1 or secp521r1 for ECC // rsapublicKey for RSA - sj=j+len; + sj = j + len; - len=getalen(OID,c->val,j); - if (len<0) return ret; - j+=skip(len); + len = getalen(OID, c->val, j); + if (len < 0) return ret; + j += skip(len); - fin=j+len; - KOID.len=len; - for (i=0; jval[j]; + fin = j + len; + if (len>KOID.max) return ret; + KOID.len = len; + for (i = 0; j < fin; j++) + KOID.val[i++] = c->val[j]; - ret.type=0; - if (OCT_comp(&ECPK,&KOID)) ret.type=ECC; - if (OCT_comp(&RSAPK,&KOID)) ret.type=RSA; + ret.type = 0; + if (OCT_comp(&ECPK, &KOID)) ret.type = X509_ECC; + if (OCT_comp(&EDPK25519, &KOID)) {ret.type = X509_ECD; ret.curve=USE_ED25519;} + if (OCT_comp(&EDPK448, &KOID)) {ret.type = X509_ECD; ret.curve=USE_ED448;} + if (OCT_comp(&RSAPK, &KOID)) ret.type = X509_RSA; + if (OCT_comp(&DILITHIUM3, &KOID)) ret.type = X509_PQ; - if (ret.type==0) return ret; + if (ret.type == 0) return ret; - if (ret.type==ECC) + if (ret.type == X509_ECC) { // which elliptic curve? - len=getalen(OID,c->val,j); - if (len<0) + len = getalen(OID, c->val, j); + if (len < 0) { - ret.type=0; + ret.type = 0; return ret; } - j+=skip(len); + j += skip(len); - fin=j+len; - KOID.len=len; - for (i=0; jval[j]; - - if (OCT_comp(&PRIME25519,&KOID)) ret.curve=C25519; /*****/ - if (OCT_comp(&PRIME256V1,&KOID)) ret.curve=NIST256; - if (OCT_comp(&SECP384R1,&KOID)) ret.curve=NIST384; - if (OCT_comp(&SECP521R1,&KOID)) ret.curve=NIST521; + fin = j + len; + if (len>KOID.max) + { + ret.type=0; + return ret; + } + KOID.len = len; + for (i = 0; j < fin; j++) + KOID.val[i++] = c->val[j]; + + if (OCT_comp(&PRIME25519, &KOID)) ret.curve = USE_ED25519; /*****/ + if (OCT_comp(&PRIME256V1, &KOID)) ret.curve = USE_NIST256; + if (OCT_comp(&SECP384R1, &KOID)) ret.curve = USE_NIST384; + if (OCT_comp(&SECP521R1, &KOID)) ret.curve = USE_NIST521; } - j=sj; // skip to actual Public Key + j = sj; // skip to actual Public Key - len=getalen(BIT,c->val,j); - if (len<0) + len = getalen(BIT, c->val, j); + if (len < 0) { - ret.type=0; + ret.type = 0; return ret; } - j+=skip(len); // + j += skip(len); // j++; len--; // skip bit shift (hopefully 0!) // extract key - if (ret.type==ECC) + if (ret.type == X509_ECC || ret.type == X509_ECD || ret.type == X509_PQ) { - key->len=len; - fin=j+len; - for (i=0; jval[i++]= c->val[j]; + if (len>key->max) + { + ret.type=0; + return ret; + } + key->len = len; + fin = j + len; + for (i = 0; j < fin; j++) + key->val[i++] = c->val[j]; } - if (ret.type==RSA) + if (ret.type == X509_PQ) + ret.curve=8*len; + if (ret.type == X509_RSA) { // Key is (modulus,exponent) - assume exponent is 65537 - len=getalen(SEQ,c->val,j); - if (len<0) + len = getalen(SEQ, c->val, j); + if (len < 0) { - ret.type=0; + ret.type = 0; return ret; } - j+=skip(len); // + j += skip(len); // - len=getalen(INT,c->val,j); // get modulus - if (len<0) + len = getalen(INT, c->val, j); // get modulus + if (len < 0) { - ret.type=0; + ret.type = 0; return ret; } - j+=skip(len); // - if (c->val[j]==0) + j += skip(len); // + if (c->val[j] == 0) { j++; len--; // remove leading zero } + if (len>key->max) + { + ret.type=0; + return ret; + } + key->len = len; + fin = j + len; + for (i = 0; j < fin; j++) + key->val[i++] = c->val[j]; - key->len=len; - fin=j+len; - for (i=0; jval[i++]= c->val[j]; - - ret.curve=8*len; + ret.curve = 8 * len; } return ret; } +// Extract Public Key from inside Certificate +pktype X509_extract_public_key(octet *c, octet *key) +{ + int ptr=0; + int pklen=X509_find_public_key(c,&ptr); + octet CC={pklen,pklen,&c->val[ptr]}; + return X509_get_public_key(&CC,key); +} + // Find pointer to main sections of cert, before extracting individual field -// Find index to issuer in cert -int X509_find_issuer(octet *c) +// Find index to issuer in cert, and its length +// This is the certificate DER encoded distinguished issuer name +int X509_find_issuer(octet *c,int *flen) { - int j,len; - j=0; - len=getalen(SEQ,c->val,j); - if (len<0) return 0; - j+=skip(len); + int j, len; + *flen=0; + j = 0; + len = getalen(SEQ, c->val, j); + if (len < 0) return 0; + j += skip(len); - if (len+j!=c->len) return 0; + if (len + j != c->len) return 0; - len=getalen(0,c->val,j); - if (len<0) return 0; - j+=skip(len)+len; //jump over version clause + len = getalen(ANY, c->val, j); + if (len < 0) return 0; + j += skip(len) + len; //jump over version clause + + len = getalen(INT, c->val, j); - len=getalen(INT,c->val,j); + if (len > 0) j += skip(len) + len; // jump over serial number clause (if there is one) - if (len>0) j+=skip(len)+len; // jump over serial number clause (if there is one) + len = getalen(SEQ, c->val, j); + if (len < 0) return 0; + j += skip(len) + len; // jump over signature algorithm len=getalen(SEQ,c->val,j); - if (len<0) return 0; - j+=skip(len)+len; // jump over signature algorithm + *flen=len+skip(len); // length of issuer return j; } @@ -568,530 +903,266 @@ int X509_find_issuer(octet *c) // Find index to validity period int X509_find_validity(octet *c) { - int j,len; - j=X509_find_issuer(c); - - len=getalen(SEQ,c->val,j); - if (len<0) return 0; - j+=skip(len)+len; // skip issuer + int j, len; + j = X509_find_issuer(c,&len); + j+=len; // skip issuer + + //len = getalen(SEQ, c->val, j); + //if (len < 0) return 0; + //j += skip(len) + len; // skip issuer return j; } -// Find index to subject in cert -int X509_find_subject(octet *c) +// Find index to subject in cert, and its length +// This is the certificate DER encoded distinguished subject name +int X509_find_subject(octet *c,int *flen) { - int j,len; - j=X509_find_validity(c); + int j, len; + *flen=0; + j = X509_find_validity(c); + + len = getalen(SEQ, c->val, j); + if (len < 0) return 0; + j += skip(len) + len; // skip validity len=getalen(SEQ,c->val,j); - if (len<0) return 0; - j+=skip(len)+len; // skip validity + *flen=len+skip(len); return j; } +int X509_self_signed(octet *c) +{ + int i,m,slen,ilen; + int ksub=X509_find_subject(c,&slen); + int kiss=X509_find_issuer(c,&ilen); + + if (slen!=ilen) return 0; + + //int sublen=getalen(SEQ,c->val,ksub); + //int isslen=getalen(SEQ,c->val,kiss); + //if (isslen!=sublen) return 0; + //ksub+=skip(sublen); + //kiss+=skip(isslen); + for (i=m=0;ival[i+ksub] - c->val[i+kiss]; + if (m!=0) return 0; + return 1; +} + // NOTE: When extracting cert information, we actually return just an index to the data inside the cert, and maybe its length // So no memory is assigned to store cert info. It is the callers responsibility to allocate such memory if required, and copy // cert information into it. // Find entity property indicated by SOID, given start of issuer or subject field. Return index in cert, flen=length of field -int X509_find_entity_property(octet *c,octet *SOID,int start,int *flen) +int X509_find_entity_property(octet *c, octet *SOID, int start, int *flen) { - int i,j,k,fin,len,tlen; + int i, j, k, fin, len, tlen; char foid[50]; /*****/ - octet FOID= {0,sizeof(foid),foid}; + octet FOID = {0, sizeof(foid), foid}; - j=start; + j = start; - tlen=getalen(SEQ,c->val,j); - if (tlen<0) return 0; - j+=skip(tlen); + tlen = getalen(SEQ, c->val, j); + if (tlen < 0) return 0; + j += skip(tlen); - for (k=j; jval,j); - if (len<0) return 0; - j+=skip(len); - len=getalen(SEQ,c->val,j); - if (len<0) return 0; - j+=skip(len); - len=getalen(OID,c->val,j); - if (len<0) return 0; - j+=skip(len); - fin=j+len; // extract OID - FOID.len=len; - for (i=0; jval[j]; - len=getalen(ANY,c->val,j); // get text, could be any type - if (len<0) return 0; - - j+=skip(len); - if (OCT_comp(&FOID,SOID)) + len = getalen(SET, c->val, j); + if (len < 0) return 0; + j += skip(len); + len = getalen(SEQ, c->val, j); + if (len < 0) return 0; + j += skip(len); + len = getalen(OID, c->val, j); + if (len < 0) return 0; + j += skip(len); + fin = j + len; // extract OID + if (len>FOID.max) return 0; + FOID.len = len; + for (i = 0; j < fin; j++) + FOID.val[i++] = c->val[j]; + len = getalen(ANY, c->val, j); // get text, could be any type + if (len < 0) return 0; + + j += skip(len); + if (OCT_comp(&FOID, SOID)) { // if its the right one return - *flen=len; + *flen = len; return j; } - j+=len; // skip over it + j += len; // skip over it } - *flen=0; /*****/ + *flen = 0; /*****/ return 0; } // Find start date of certificate validity period -int X509_find_start_date(octet *c,int start) +int X509_find_start_date(octet *c, int start) { - int j,len; - j=start; + int j, len; + j = start; - len=getalen(SEQ,c->val,j); - if (len<0) return 0; - j+=skip(len); + len = getalen(SEQ, c->val, j); + if (len < 0) return 0; + j += skip(len); - len=getalen(UTC,c->val,j); - if (len<0) return 0; - j+=skip(len); + len = getalen(UTC, c->val, j); + if (len < 0) + { // could be generalised time + len = getalen(GTM, c->val, j); + if (len<0) return 0; + j += skip(len); + j += 2; // skip century + } + else j += skip(len); return j; } // Find expiry date of certificate validity period -int X509_find_expiry_date(octet *c,int start) +int X509_find_expiry_date(octet *c, int start) { - int j,len; - j=start; + int j, len; + j = start; - len=getalen(SEQ,c->val,j); - if (len<0) return 0; - j+=skip(len); + len = getalen(SEQ, c->val, j); + if (len < 0) return 0; + j += skip(len); - len=getalen(UTC,c->val,j); - if (len<0) return 0; - j+=skip(len)+len; + len = getalen(UTC, c->val, j); + if (len < 0) + { + len = getalen(GTM,c->val,j); + if (len<0) return 0; + } + j += skip(len) + len; - len=getalen(UTC,c->val,j); - if (len<0) return 0; - j+=skip(len); + len = getalen(UTC, c->val, j); + if (len < 0) + { // could be generalised time + len = getalen(GTM, c->val,j); + if (len<0) return 0; + j+=skip(len); + j+=2; // skip century + } + else j += skip(len); return j; } -void print_out(char *des,octet *c,int index,int len) +int X509_find_extensions(octet *c) { - int i; - printf("%s [",des); - for (i=0; ival[index+i]); - printf("]\n"); -} + int j, len; + j=X509_find_subject(c,&len); + j+=len; // skip subject + //len = getalen(SEQ, c->val, j); + //if (len<0) return 0; + //j += skip(len)+len; // skip subject + + len = getalen(SEQ, c->val, j); + if (len<0) return 0; + j += skip(len)+len; // skip public key -void print_date(char *des,octet *c,int index) -{ - int i=index; - printf("%s [",des); - if (i==0) printf("]\n"); - else printf("20%c%c-%c%c-%c%c %c%c:%c%c:%c%c]\n",c->val[i],c->val[i+1],c->val[i+2],c->val[i+3],c->val[i+4],c->val[i+5],c->val[i+6],c->val[i+7],c->val[i+8],c->val[i+9],c->val[i+10],c->val[i+11]); + if (j>=c->len) return 0; + return j; } - -#ifdef HAS_MAIN - -/* This simple driver program is hard-wired to support just one elliptic curve and one - RSA bit length. To change replace the text string NIST256 in the main program to - another curve and 2048 to some other value, where the curve and the RSA bit length - are suppported by the library. Of course a more elaborate program could support - muliple curves simultaneously */ - -#define CHOICE NIST256 - - - -/* test driver program */ -// Sample Certs. Uncomment one CA cert and one example cert. Note that AMCL library must be built to support given curve. -// Sample Certs all created using OpenSSL - see http://blog.didierstevens.com/2008/12/30/howto-make-your-own-cert-with-openssl/ -// Note - SSL currently only supports NIST curves. Howevever version 1.1.0 of OpenSSL now supports C25519 - -#if CHOICE==NIST256 - -#include "ecdh_NIST256.h" -#include "rsa_2048.h" - -// ** CA is RSA 2048-bit based - for use with NIST256 build of library - assumes use of SHA256 in Certs -// RSA 2048 Self-Signed CA cert -char ca_b64[]="MIIDuzCCAqOgAwIBAgIJAP44jcM1MOROMA0GCSqGSIb3DQEBCwUAMHQxCzAJBgNVBAYTAklFMRAwDgYDVQQIDAdJcmVsYW5kMQ8wDQYDVQQHDAZEdWJsaW4xITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEfMB0GCSqGSIb3DQEJARYQbXNjb3R0QGluZGlnby5pZTAeFw0xNTExMjYwOTUwMzlaFw0yMDExMjUwOTUwMzlaMHQxCzAJBgNVBAYTAklFMRAwDgYDVQQIDAdJcmVsYW5kMQ8wDQYDVQQHDAZEdWJsaW4xITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEfMB0GCSqGSIb3DQEJARYQbXNjb3R0QGluZGlnby5pZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANUs7/nri9J8zw8rW8JVszXP0ZqeLoQJaq2X28ebm8x5VT3okr9rnBjFjpx0YKQCAFQf8iSOOYuNpDvtZ/YpsjPbk2rg5sLY9G0eUMqrTuZ7moPSxnrXS5evizjD9Z9HqaqeNEYD3sPouPg+lhU1oAUQjUTJVFhEr1x0EnSEYbbrWtY9ZDSuZv+d4NIeqqPOYFd1yZc+LYZyQbAAQqwRLNPZH/rnIykLa6I7w7mGT7H6SBz2O09BtgpTHhalL40ecXa4ZOEze0xwzlc+mEFIrnmdadg3vQrJt42RVbo3LN6RfDIqUZOMOtQW/53pUR1lIpCwVWJTiOpmSEIEqhhjFq0CAwEAAaNQME4wHQYDVR0OBBYEFJrz6LHeT6FcjRahpUC3hAMxKRTCMB8GA1UdIwQYMBaAFJrz6LHeT6FcjRahpUC3hAMxKRTCMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBADqkqCYVa3X8XO9Ufu6XIUoZafFPRjSeJXvEIWqlbm7ixJZ2FPOvf2eMc5RCZYigNKhsxru5Ojw0lPcpa8DDmEsdZDf7p0vlmf7T7xH9gtoInh4DzgI8HRHFc8R/z2/jLX7nlLoopKX5yp7F1gRACg0pd4tGpQ6EnBNcYZZghFH9UIRDmx+vDlwDCu8vyRPt35orrEiI4XGq/QkvxxAb5YWxQ4i06064ULfyCI7suu3KoobdM1aAaA8zhpOOBXKbq+Wi9IGFe/wiEMHLmfHdt9CBTjIWb//IHji4RT05kCmTVrx97pb7EHafuL3L10mM5cpTyBWKnb4kMFtx9yw+S2U="; -// an RSA 2048 CA-signed cert -//char cert_b64[]="MIIDcjCCAloCAQEwDQYJKoZIhvcNAQELBQAwdDELMAkGA1UEBhMCSUUxEDAOBgNVBAgMB0lyZWxhbmQxDzANBgNVBAcMBkR1YmxpbjEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMR8wHQYJKoZIhvcNAQkBFhBtc2NvdHRAaW5kaWdvLmllMB4XDTE1MTEyNjEwMzQzMFoXDTE3MTEyNTEwMzQzMFowgYkxCzAJBgNVBAYTAklFMRAwDgYDVQQIDAdJcmVsYW5kMQ8wDQYDVQQHDAZEdWJsaW4xETAPBgNVBAoMCENlcnRpVm94MQ0wCwYDVQQLDARMYWJzMQ0wCwYDVQQDDARNSUtFMSYwJAYJKoZIhvcNAQkBFhdtaWtlLnNjb3R0QGNlcnRpdm94LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMIoxaQHFQzfyNChrw+3i7FjRFMHZ4zspkjkAcJW21LdBCqrxU+sdjyBoSFlrlafQOHshbrEP93AKX1bfaYbuV4fzq7OlRaLxaK+b+xrOJdewMI2WZ5OwEzj3onZATISogIoB6dTdzJ41NuxuMqQ/DqOnVrRA0SoIespbQhB8FGHBLw0hJATBzUk+bqOIt0HmnMp2EbYgtuG4lYINU/lD3Qt16SunUukWRLtxqJkioie+dkhP2zm+bOlSVmeQb4Wp8AI14OKkTfkdYC8qCxb5eabg90Q33rQUhNwRQHhHwopZwD/BgodasoSrPfwUlj0awh6y87eMGcik5Q/mjkCk5MCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAFrd7R/67ClkbLhpiX++6QTOa47siUAB9v+Qil9hZfhPNeeM589ixYkD4zH5pOK2B0ea+CXEKkanQ6lXx9KV86yS7fq6Yww7wO0diecusHd0+P82i46Tq0nm8nlsnAuhYoFRUGa2m2DkB1HSsB0ts8DjzFLySonFjSSLHDU0ox9/uFbJMzipy3ijAA4XM0N4jRrUfrmxpA7DOOsbEbGkvvB7VK9+s9PHE/4dJTwhSteplUnhxVFkkDo/JwaLx4/IEQRlCF3KEQ5s3AwRHnbrIjOY2yONxHBtJEp7QN5aOHruwvMNRNheCBPiQJyLitUsFGr4voANmobkrFgYtu0tRMQ=="; -// an ECC 256 CA-signed cert -char cert_b64[]="MIICojCCAYoCAQMwDQYJKoZIhvcNAQELBQAwdDELMAkGA1UEBhMCSUUxEDAOBgNVBAgMB0lyZWxhbmQxDzANBgNVBAcMBkR1YmxpbjEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMR8wHQYJKoZIhvcNAQkBFhBtc2NvdHRAaW5kaWdvLmllMB4XDTE1MTEyNjEzNDcyOVoXDTE3MTEyNTEzNDcyOVowgYQxCzAJBgNVBAYTAklFMRAwDgYDVQQIDAdJcmVsYW5kMQ8wDQYDVQQHDAZEdWJsaW4xETAPBgNVBAoMCENlcnRpdm94MQ0wCwYDVQQLDARMYWJzMQ8wDQYDVQQDDAZtc2NvdHQxHzAdBgkqhkiG9w0BCQEWEG1zY290dEBpbmRpZ28uaWUwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATO2iZiQZsXxzwBKnufKfZcsctNXZ4PmfJm638PmX9DQ3Xdb+nD5VxiOakNcB9xf5im8CriiOF5Z/7yPGyzUMbdMA0GCSqGSIb3DQEBCwUAA4IBAQAK5fMgGCCiPts8hMUZvYDpu8hd7qtPKPBc10QUccHb7PGrhqf/Ex2Gpj1aaURmx7SGZG0HX97LtkdW8KQpEoyaa60r7cjVA589TznxXKSGg5ggVoFJNpuZUm7VcolLjwIgTxtGbPzrvVMiZ4cl4PwFePXVKTl4f8XkOFX5gLmVSuCf729lEBmpx3IzqGmTjmnBixaApUElOKVeL7hiUKP3TqMUxZN+QNJBq4Mh9K9h4Sks2oneLwBwhMqQvpmcOb/7SucJn5N0IgJoGaMbfX0oCJJID1NSbagUSbFD1XciR2Ng9VtvnRP+htmEQ7jtww8phFdrWt5M5zPGOHUppqDx"; - -// ** CA is ECC 256 based - for use with NIST256 build of library -// ECC 256 Self-Signed CA cert -//char ca_b64[]="MIIB7TCCAZOgAwIBAgIJANp4nGS/VYj2MAoGCCqGSM49BAMCMFMxCzAJBgNVBAYTAklFMRAwDgYDVQQIDAdJcmVsYW5kMQ8wDQYDVQQHDAZEdWJsaW4xITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0xNTExMjYxMzI0MTBaFw0yMDExMjUxMzI0MTBaMFMxCzAJBgNVBAYTAklFMRAwDgYDVQQIDAdJcmVsYW5kMQ8wDQYDVQQHDAZEdWJsaW4xITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABPb6IjYNKyfbEtL1aafzW1jrn6ALn3PnGm7AyX+pcvwG0GKmb3Z/uHzhT4GysNE0/GB1n4Y/mrORQIm2X98rRs6jUDBOMB0GA1UdDgQWBBSfXUNkgJVklIhuXq4DCnVYhsdzwDAfBgNVHSMEGDAWgBSfXUNkgJVklIhuXq4DCnVYhsdzwDAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMCA0gAMEUCIQDrZJ1tshwTl/jabU2i49EOgbWe0ZgE3QZywJclf5IVwwIgVmz79AAf7e098lyrOKYAqbwjHVyMZGfmkNNGIuIhp/Q="; -// an ECC 256 CA-signed cert -//char cert_b64[]="MIIBvjCCAWQCAQEwCgYIKoZIzj0EAwIwUzELMAkGA1UEBhMCSUUxEDAOBgNVBAgMB0lyZWxhbmQxDzANBgNVBAcMBkR1YmxpbjEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMB4XDTE1MTEyNjEzMjc1N1oXDTE3MTEyNTEzMjc1N1owgYIxCzAJBgNVBAYTAklFMRAwDgYDVQQIDAdJcmVsYW5kMQ8wDQYDVQQHDAZEdWJsaW4xETAPBgNVBAoMCENlcnRpdm94MQ0wCwYDVQQLDARMYWJzMQ0wCwYDVQQDDARtaWtlMR8wHQYJKoZIhvcNAQkBFhBtc2NvdHRAaW5kaWdvLmllMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEY42H52TfWMLueKB1o2Sq8uKaKErbHJ2GRAxrnJdNxex0hxZF5FUx7664BbPUolKhpvKTnJxDq5/gMqXzpKgR6DAKBggqhkjOPQQDAgNIADBFAiEA0ew08Xg32g7BwheslVKwXo9XRRx4kygYha1+cn0tvaUCIEKCEwnosZlAckjcZt8aHN5zslE9K9Y7XxTErTstthKc"; -// an RSA 2048 CA-signed cert -//char cert_b64[]="MIICiDCCAi4CAQIwCgYIKoZIzj0EAwIwUzELMAkGA1UEBhMCSUUxEDAOBgNVBAgMB0lyZWxhbmQxDzANBgNVBAcMBkR1YmxpbjEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMB4XDTE1MTEyNjEzMzcwNVoXDTE3MTEyNTEzMzcwNVowgYExCzAJBgNVBAYTAklFMQ8wDQYDVQQIDAZJZWxhbmQxDzANBgNVBAcMBkR1YmxpbjERMA8GA1UECgwIQ2VydGl2b3gxDTALBgNVBAsMBExhYnMxDTALBgNVBAMMBE1pa2UxHzAdBgkqhkiG9w0BCQEWEG1zY290dEBpbmRpZ28uaWUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCjPBVwmPg8Gwx0+8xekmomptA0BDwS7NUfBetqDqNMNyji0bSe8LAfpciU7NW/HWfUE1lndCqSDDwnMJmwC5e3GAl/Bus+a+z8ruEhWGbn95xrHXFkOawbRlXuS7UcEQCvPr8KQHhNsg4cyV7Hn527CPUl27n+WN8/pANo01cTN/dQaK87naU0Mid09vktlMKSN0zyJOnc5CsaTLs+vCRKJ9sUL3d4IQIA2y7gvrTe+iY/QI26nqhGpNWYyFkAdy9PdHUEnDI6JsfF7jFh37yG7XEgDDA3asp/oi1T1+ZoASj2boL++opdqCzDndeWwzDWAWuvJ9wULd80ti6x737ZAgMBAAEwCgYIKoZIzj0EAwIDSAAwRQIgCDwgl98+9moBo+etaLt8MvB/z5Ti6i9neRTZkvoFl7YCIQDq//M3OB757fepErRzIQo3aFAFYjOooi6WdSqP3XqGIg=="; - -#endif - -#if CHOICE==NIST384 - -#include "ecdh_NIST384.h" -#include "rsa_3072.h" - -// ** CA is RSA 3072-bit based - for use with NIST384 build of library - assumes use of SHA384 in Certs -// RSA 3072 Self-Signed CA cert -char ca_b64[]="MIIElzCCAv+gAwIBAgIJAJA+8OyEeK4FMA0GCSqGSIb3DQEBDAUAMGIxCzAJBgNVBAYTAklFMRAwDgYDVQQIDAdJcmVsYW5kMQ8wDQYDVQQHDAZEdWJsaW4xITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDENMAsGA1UEAwwETWlrZTAeFw0xNTExMjYxNDQ0MDBaFw0yMDExMjUxNDQ0MDBaMGIxCzAJBgNVBAYTAklFMRAwDgYDVQQIDAdJcmVsYW5kMQ8wDQYDVQQHDAZEdWJsaW4xITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDENMAsGA1UEAwwETWlrZTCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBANvNO8ahsanxzqwkp3A3bujwObJoP3xpOiAAxwGbW867wx4EqBjPRZP+Wcm9Du6e4Fx9U7tHrOLocIUUBcRrmxUJ7Z375hX0cV9yuoYPNv0o2klJhB8+i4YXddkOrSmDLV4r46Ytt1/gjImziat6ZJALdd/uIuhaXwjzy1fFqSEBpkzhrFwFP9MG+5CgbRQed+YxZ10l/rjk+h3LKq9UFsxRCMPYhBFgmEKAVTMnbTfNNxawTRCKtK7nxxruGvAEM+k0ge5rvybERQ0NxtizefBSsB3Q6QVZOsRJiyC0HQhE6ZBHn4h3A5nHUZwPeh71KShw3uMPPB3Kp1pb/1Euq8azyXSshEMPivvgcGJSlm2b/xqsyrT1tie82MqB0APYAtbx3i5q8p+rD143NiNO8fzCq/J+EV82rVyvqDxf7AaTdJqDbZmnFRbIcrLcQdigWZdSjc+WxrCeOtebRmRknuUmetsCUPVzGv71PLMUNQ2qEiq8KGWmnMBJYVMl96bPxwIDAQABo1AwTjAdBgNVHQ4EFgQUsSjrHeZ5TNI2tMcQd6wUnFpU8DcwHwYDVR0jBBgwFoAUsSjrHeZ5TNI2tMcQd6wUnFpU8DcwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQwFAAOCAYEADlnC1gYIHpVf4uSuBpYNHMO324hhGajHNraHYQAoYc0bW4OcKi0732ib5CHDrV3LCxjxF4lxZVo61gatg5LnfJYldXc0vP0GQRcaqC6lXlLb8ZJ0O3oPgZkAqpzc+AQxYW1wFxbzX8EJU0stSwAuxkgs9bwg8tTxIhDutrcjQl3osnAqGDyM+7VAG5QLRMzxiZumyD7s/xBUOa+L6OKXf4QRr/SH/rPU8H+ENaNkv4PApSVzCgTBPOFBIzqEuO4hcQI0laUopsp2kK1w6wYB5oY/rR/O6lNNfB2WEtfdIhdbQru4cUE3boKerM8Mjd21RuerAuK4X8cbDudHIFsaopGSNuzZwPo/bu0OsmZkORxvdjahHJ0G3/6jM6nEDoIy6mXUCGOUOMhGQKCa8TYlZdPKz29QIxk6HA1wCA38MxUo/29Z7oYw27Mx3x8Gcr+UA4vc+oBN3IEzRmhRZKAYQ10MhYPx3NmYGZBDqHvT06oG5hysTCtlVzx0Tm+o01JQ"; -// an RSA 3072 CA-signed cert -//char cert_b64[]="MIIEWzCCAsMCAQYwDQYJKoZIhvcNAQEMBQAwYjELMAkGA1UEBhMCSUUxEDAOBgNVBAgMB0lyZWxhbmQxDzANBgNVBAcMBkR1YmxpbjEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMQ0wCwYDVQQDDARNaWtlMB4XDTE1MTEyNjE0NDY0MloXDTE3MTEyNTE0NDY0MlowgYQxCzAJBgNVBAYTAklFMRAwDgYDVQQIDAdJcmVsYW5kMQ8wDQYDVQQHDAZEdWJsaW4xETAPBgNVBAoMCENlcnRpdm94MQ0wCwYDVQQLDARMYWJzMQ8wDQYDVQQDDAZtc2NvdHQxHzAdBgkqhkiG9w0BCQEWEG1zY290dEBpbmRpZ28uaWUwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQC6SrDiE4BpTEks1YpX209q8iH0dfvhGO8hi1rGYFYnz+eeiOvPdXiCdIPVPbGwxQGMEnZQV1X0KupYJw3LR2EsXhN4LZBxnQZmDvUXsTU+Ft/CKZUxVoXpNMxzwl70RC6XeUpPxvdPXa78AnfLL/DsOKsxCfNaKYZZ6G53L6Y69+HrCbyM7g2KrZ9/K/FXS1veMpRj9EbA6Mcdv1TUDNK2fTDV952AQO3kC3+PqywdVgPvntraAoQomrni+tcFW7UXe2Sk7DRcF/acBSuo2UtP3m9UWNL+8HOXvtRqmhns55Vj4DxKuPln759UBS7WZ11apCvC3BvCHR/k3WRf9PQWnW2cmT73/kEShvTRi8h7F9RWvYTEF1MuwSVy+l51q8O3rJU4XxnLm/YbtIGXZUf5Rqb0985zQkA+6rip/OSc8X5a3OV3kp38U7tXJ5sqBMg9RdIIz42cmiRLG5NYSj0/T6zjYEdwj3SYEBoPN/7UGSmhu8fdxS7JYPNpOsgeiu8CAwEAATANBgkqhkiG9w0BAQwFAAOCAYEAyxxEg0hWLFuN2fiukX6vqzSDx5Ac8w1JI4W/bamRd7iDZfHQYqyPDZi9s07I2PcGbByj2oqoyGiIEBLbsljdIEF4D229h2kisn1gA9O+0IM44EgjhBTUoNDgC+SbfJrXlU2GZ1XI3OWjbK7+1wiv0NaBShbbiPgSdjQBP8S+9W7lyyIrZEM1J7maBdepie1BS//DUDmpQzEi0UlB1J+HmQpyZsnT97J9uIPKsK4t2/+iOiknl6iS4GzAQKMLqj2yIBRf/O44ZZ6UZIKLtI4PCVS/8H5Lrg3AC0kr4ZkPAXzefUiTwyLVkqYSxSSTvtb3BpgOxIbmA6juFid0rvUyjN4fuDQkxl3PZyQwIHjpz33HyKrmo4BZ8Dg4JT8LCsQgd0AaD3r0QOS5FdLhkb+rD8EMSsCoOCEtPI6lqLJCrGOQWj7zbcUdPOEsczWMI9hSfK3u/P9+gOUBUFkb0gBIn3WvNuHifIHpsZ5bzbR+SGtu5Tgc7CCCPyNgz1Beb247"; -// an ECC 384 CA-signed cert -char cert_b64[]="MIIDCDCCAXACAQcwDQYJKoZIhvcNAQEMBQAwYjELMAkGA1UEBhMCSUUxEDAOBgNVBAgMB0lyZWxhbmQxDzANBgNVBAcMBkR1YmxpbjEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMQ0wCwYDVQQDDARNaWtlMB4XDTE1MTEyNjE1MzU1M1oXDTE3MTEyNTE1MzU1M1owYDELMAkGA1UEBhMCSUUxEDAOBgNVBAgMB0lyZWxhbmQxDzANBgNVBAcMBkR1YmxpbjEQMA4GA1UECgwHQ2VydGl2bzENMAsGA1UECwwETGFiczENMAsGA1UEAwwEbWlrZTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJ1J+FT5mxxYEM4aYKM0CvZHmh8JFXzoBmzibabrvyTz79+1QOrR+6MEEsKtmJIYPJi+GsQ0PmjF2HmJncM1zeQh7DQYJf2Xc8p5Vjd8//6YREBVfN3UIyrl87MSucy+mjANBgkqhkiG9w0BAQwFAAOCAYEAmuwa64+K1qlCELpcnCyWwMhSb+Zsw0Hh6q/BfxalZhsX1UFEwE9nHoVJcokaEEYF4u4AYXU5rdysRHxYBfgMbohguTT7sJwCfve2JqpqvhQOkGDG1DB4Ho4y7NPPYB2+UMd7JMD0TOcHXdgQ8FtAE0ClD8VkW0gAC0lCrbQbynfLoUjIWqg3w2g79hvdZPgRt208nFiHuezynOaEFePoXl8CxHInsxAnMaJn2fEs5/QH67pwD65mPdNFsvlr0zdzYcceqEmEHpRAXFOQAJtffGjWAGGX/CsghLuqlpdCiTGA1B53XoXKJvArr/kHpTNMsU1NnkQIHZ5n4USCo4QgL6n9nwem7U2mYBYjmxPi5Y3JJnTZz4zUnv0bD0vSwoivnFZox9H6qTAkeIX1ojJ2ujxWHNOMvOFb6nU2gqNZj2vYcO38OIrK9gwM9lm4FF20YBufh+WOzQthrHJv0YuQt3NuDQEMkvz+23YvzZlr+e2XqDlMhyR01Kk0MXeLGGcv"; - -// ** CA is ECC 384 based - - for use with NIST384 build of library - assumes use of SHA384 in Certs -// ECC 384 Self-Signed CA Cert -//char ca_b64[]="MIICSTCCAc6gAwIBAgIJAIwHpOFSZLXnMAoGCCqGSM49BAMDMGIxCzAJBgNVBAYTAklFMRAwDgYDVQQIDAdJcmVsYW5kMQ8wDQYDVQQHDAZEdWJsaW4xITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDENMAsGA1UEAwwEbWlrZTAeFw0xNTExMjYxNTQ0NTlaFw0yMDExMjUxNTQ0NTlaMGIxCzAJBgNVBAYTAklFMRAwDgYDVQQIDAdJcmVsYW5kMQ8wDQYDVQQHDAZEdWJsaW4xITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDENMAsGA1UEAwwEbWlrZTB2MBAGByqGSM49AgEGBSuBBAAiA2IABOEPMYBqzIn1hJAMZ0aEVxQ08gBF2aSfWtEJtmKj64014w7VfWdeFQSIMP9SjmhatFbAvxep8xgcwbeAobGTqCgUp+0EdFZR1ktKSND/S+UDU1YSNCFRvlNTJ6YmXUkW36NQME4wHQYDVR0OBBYEFDQxIZoKNniNuW91UMJ1KWEjs045MB8GA1UdIwQYMBaAFDQxIZoKNniNuW91UMJ1KWEjs045MAwGA1UdEwQFMAMBAf8wCgYIKoZIzj0EAwMDaQAwZgIxANbml6sp5A92qQiCM/OtBf+TbXpSpIO83TuNP9V2lsphp0CEX3KwAuqBXB95m9/xWAIxAOXAT2LqieSbUh4fpxcdaeY01RoGtD2AQch1a6BuIugcQqTfqLcXy7D51R70R729sA=="; -// an ECC 384 CA-signed cert -//char cert_b64[]="MIICCjCCAZACAQgwCgYIKoZIzj0EAwMwYjELMAkGA1UEBhMCSUUxEDAOBgNVBAgMB0lyZWxhbmQxDzANBgNVBAcMBkR1YmxpbjEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMQ0wCwYDVQQDDARtaWtlMB4XDTE1MTEyNjE1NTIxMFoXDTE3MTEyNTE1NTIxMFowgYIxCzAJBgNVBAYTAklFMRAwDgYDVQQIDAdJcmVsYW5kMQ8wDQYDVQQHDAZEdWJsaW4xETAPBgNVBAoMCENlcnRpdm94MQ0wCwYDVQQLDARMYWJzMQ0wCwYDVQQDDARtaWtlMR8wHQYJKoZIhvcNAQkBFhBtc2NvdHRAaW5kaWdvLmllMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEf2Qm6jH2U+vhAApsMqH9gzGCH8rk+mUwFSD3Uud4NiyPBqrJRC1eetVvr3cYb6ucDTa15km6QKvZZrsRW+Z4ZpryoEE6esmD4XPLrtrOtoxtxFNRhiMmT/M9zcrfMJC5MAoGCCqGSM49BAMDA2gAMGUCMF0x6PAvvnJR3riZdUPC4OWFC2K3eiz3QuLCdFOZVIqX7mkLftdS8BtzusXWMMgFCQIxALJNMKLs39P9wYQHu1C+v9ieltQr20C+WVYxqUvgL/KTdxd9dzc3wseZRDT1CydqOA=="; -// an RSA 3072 CA-signed cert -//char cert_b64[]="MIIDFjCCAp4CAQkwCgYIKoZIzj0EAwMwYjELMAkGA1UEBhMCSUUxEDAOBgNVBAgMB0lyZWxhbmQxDzANBgNVBAcMBkR1YmxpbjEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMQ0wCwYDVQQDDARtaWtlMB4XDTE1MTEyNjE2MTYwNloXDTE3MTEyNTE2MTYwNlowYzELMAkGA1UEBhMCSUUxEDAOBgNVBAgMB0lyZWxhbmQxDzANBgNVBAcMBkR1YmxpbjERMA8GA1UECgwIQ2VydGl2b3gxDTALBgNVBAsMBGxhYnMxDzANBgNVBAMMBmtlYWxhbjCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAK5QhVjR+UGt3ZWPSGicpviqaOhxXmmvOepdl5Seqr+Iweb3IuEDgtHGwrw/EEgWlKPfS/2LW9ncptdNbVQh7+2rojj7ZtedrAK5p7I9b22f2U3sSHIqjtTT0BjqzL0qEwy/ATqbf93Tcr3yT0Ygh3yzbvn4zodrWQZK8kkN3PQKkiHBCuIxo+8MlTs8d99dl1hbJ84MYZuPmhrkB4oLEAt8+srtL+a4Yd0wPhuCYrLjBnYkD9TlcWLWWh8/iwXiznrY8gQsXSveQNzQjcmHilZrTlTL2dnyI2v7BAXXHSwo6UeES0n064fnYTr3JB0GArMcty6RD3E7xr64HNzzTE2+8cDxufNvU0tq2Z72oZ9cAReHUL5P6mLfORI+AhtCHrXGJch/F07ZX9h8UFpzok8NK5++Q7lHKuezTYRRPlDL5hDB3BUpBwvILdqujcbNil04cuLRBNT/WgqRXEBRjlHLgZaLChFV2VSJ9Z1Uke2lfm5X2O0XPQLhjMSiuvr4HwIDAQABMAoGCCqGSM49BAMDA2YAMGMCLxHSQAYP2EsuIpR4TzDDSIlsw4BBsD7W0ZfH91v9J0j5UWQJD/yNjMtyA2Qlkq/0AjB+SJQbLgycNJH5SnR/X5wx26/62ln9s0swUtlCYVtNzyEQ3YRHSZbmTbh16RUT7Ak="; - -#endif - -#if CHOICE==NIST521 - -#include "ecdh_NIST521.h" -#include "rsa_4096.h" - -// ** CA is ECC 521 based - - for use with NIST521 build of library - assumes use of SHA512 in Certs -// ECC 521 Self-Signed CA Cert -char ca_b64[]="MIIC+TCCAlqgAwIBAgIJAKlppiHsRpY8MAoGCCqGSM49BAMEMIGUMQswCQYDVQQGEwJJRTEQMA4GA1UECAwHSXJlbGFuZDEPMA0GA1UEBwwGRHVibGluMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDTALBgNVBAsMBExhYnMxDzANBgNVBAMMBm1zY290dDEfMB0GCSqGSIb3DQEJARYQbXNjb3R0QGluZGlnby5pZTAeFw0xNTEyMDExMzE5MjZaFw0yMDExMzAxMzE5MjZaMIGUMQswCQYDVQQGEwJJRTEQMA4GA1UECAwHSXJlbGFuZDEPMA0GA1UEBwwGRHVibGluMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDTALBgNVBAsMBExhYnMxDzANBgNVBAMMBm1zY290dDEfMB0GCSqGSIb3DQEJARYQbXNjb3R0QGluZGlnby5pZTCBmzAQBgcqhkjOPQIBBgUrgQQAIwOBhgAEAKUj6Qa4Vr1vyango8XHlLIIEzY9IVppdpGUrMlNfo0Spu+AXGhnluwJTZXOYLi8jSIPEAL7vuwS5H6uPPIz1QWXALRETVYAQfK0pIfPHq+edTHVTXMcAUpdNla2d4LwYO7HpkSQFHd7aaDN3yVhSL2J0LBLgy0wGkEHuyK1O2r0xNu6o1AwTjAdBgNVHQ4EFgQU966PLshKffU/NRCivMmNq8RiRkAwHwYDVR0jBBgwFoAU966PLshKffU/NRCivMmNq8RiRkAwDAYDVR0TBAUwAwEB/zAKBggqhkjOPQQDBAOBjAAwgYgCQgHkLczeTWXq5BfY0bsTOSNU8bYy39OhiQ8wr5rlXY0zOg0fDyokueL4dhkXp8FjbIyUfQBY5OMxjtcn2p+cXU+6MwJCAci61REgxZvjpf1X8pGeSsOKa7GhfsfVnbQm+LQmjVmhMHbVRkQ4h93CENN4MH/86XNozO9USh+ydTislAcXvCb0"; -// an ECC 521 CA-signed cert -char cert_b64[]="MIICZjCCAccCAQMwCgYIKoZIzj0EAwQwgZQxCzAJBgNVBAYTAklFMRAwDgYDVQQIDAdJcmVsYW5kMQ8wDQYDVQQHDAZEdWJsaW4xITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDENMAsGA1UECwwETGFiczEPMA0GA1UEAwwGbXNjb3R0MR8wHQYJKoZIhvcNAQkBFhBtc2NvdHRAaW5kaWdvLmllMB4XDTE1MTIwMTEzMjkxN1oXDTE3MTEzMDEzMjkxN1owYTELMAkGA1UEBhMCSUUxEDAOBgNVBAgMB0lyZWxhbmQxDzANBgNVBAcMBkR1YmxpbjERMA8GA1UECgwIQ2VydGlWb3gxDTALBgNVBAsMBExhYnMxDTALBgNVBAMMBE1pa2UwgZswEAYHKoZIzj0CAQYFK4EEACMDgYYABAAva/N4kP2LMSGJZ5tvULlfdNx2M/+xYeCrQkuFmY8sG+mdcUAaSx819fztn2jz1nfdTJnuj79AhfUOL8hlTW14BwErp3DnqWa7Y/rpSJP+AsnJ2bZg4yGUDfVy/Q0AQychSzJm2oGRfdliyBIc+2SoQJ/Rf0ZVKVJ5FfRbWUUiKqYUqjAKBggqhkjOPQQDBAOBjAAwgYgCQgFE1Y7d9aBdxpZqROtkdVNG8XBCTSlMX0fISWkSM8ZEiQfYf7YgXzLjk8wHnv04Mv6kmAuV0V1AHs2M0/753CYEfAJCAPZo801McsGe+3jYALrFFw9Wj7KQC/sFEJ7/I+PYyJtrlfTTqmV0IFKdJzjEsk7ic+Gd4Nbs6kIe1GyYbrcyC4wT"; - -#endif - -char io[5000]; -octet IO= {0,sizeof(io),io}; - -#define MAXMODBYTES 72 -#define MAXFFLEN 16 - -char sig[MAXMODBYTES*MAXFFLEN]; -octet SIG= {0,sizeof(sig),sig}; - -char r[MAXMODBYTES]; -octet R= {0,sizeof(r),r}; - -char s[MAXMODBYTES]; -octet S= {0,sizeof(s),s}; - -char cakey[MAXMODBYTES*MAXFFLEN]; -octet CAKEY= {0,sizeof(cakey),cakey}; - -char certkey[MAXMODBYTES*MAXFFLEN]; -octet CERTKEY= {0,sizeof(certkey),certkey}; - -char h[5000]; -octet H= {0,sizeof(h),h}; - -char hh[5000]; -octet HH= {0,sizeof(hh),hh}; - -char hp[RFS_2048]; -octet HP= {0,sizeof(hp),hp}; - - -int main() +int X509_find_extension(octet *c, octet *SOID, int start, int *flen) { - int res,len,sha; - int c,ic; - rsa_public_key_2048 PK; - pktype st,ca,pt; - - printf("First check signature on self-signed cert and extract CA public key\n"); - OCT_frombase64(&IO,ca_b64); - printf("CA Self-Signed Cert= \n"); - OCT_output(&IO); - printf("\n"); - - st=X509_extract_cert_sig(&IO,&SIG); // returns signature type - - if (st.type==0) - { - printf("Unable to extract cert signature\n"); - return 0; - } - - if (st.type==ECC) - { - OCT_chop(&SIG,&S,SIG.len/2); - OCT_copy(&R,&SIG); - printf("ECC SIG= \n"); - OCT_output(&R); - OCT_output(&S); - printf("\n"); - } - - if (st.type==RSA) - { - printf("RSA SIG= \n"); - OCT_output(&SIG); - printf("\n"); - } - - if (st.hash==H256) printf("Hashed with SHA256\n"); - if (st.hash==H384) printf("Hashed with SHA384\n"); - if (st.hash==H512) printf("Hashed with SHA512\n"); - -// Extract Cert from signed Cert - - c=X509_extract_cert(&IO,&H); - - printf("\nCert= \n"); - OCT_output(&H); - printf("\n"); + int i, j, k, fin, len, tlen, nj; + char foid[50]; /*****/ + octet FOID = {0, sizeof(foid), foid}; -// show some details - printf("Issuer Details\n"); - ic=X509_find_issuer(&H); - c=X509_find_entity_property(&H,&ON,ic,&len); - print_out("owner=",&H,c,len); - c=X509_find_entity_property(&H,&CN,ic,&len); - print_out("country=",&H,c,len); - c=X509_find_entity_property(&H,&EN,ic,&len); - print_out("email=",&H,c,len); - printf("\n"); + j = start; - ca=X509_extract_public_key(&H,&CAKEY); + tlen = getalen(EXT, c->val, j); + if (tlen < 0) return 0; + j += skip(tlen); - if (ca.type==0) - { - printf("Not supported by library\n"); - return 0; - } - if (ca.type!=st.type) - { - printf("Not self-signed\n"); - } + tlen = getalen(SEQ, c->val, j); + if (tlen < 0) return 0; + j += skip(tlen); - if (ca.type==ECC) + for (k = j; j < k + tlen;) { - printf("EXTRACTED ECC PUBLIC KEY= \n"); - OCT_output(&CAKEY); - } - if (ca.type==RSA) - { - printf("EXTRACTED RSA PUBLIC KEY= \n"); - OCT_output(&CAKEY); - } - printf("\n"); - -// Cert is self-signed - so check signature - - printf("Checking Self-Signed Signature\n"); - if (ca.type==ECC) - { - if (ca.curve!=CHOICE) - { - printf("Curve is not supported\n"); - return 0; - } - res=ECP_NIST256_PUBLIC_KEY_VALIDATE(1,&CAKEY); - if (res!=0) - { - printf("ECP Public Key is invalid!\n"); - return 0; - } - else printf("ECP Public Key is Valid\n"); - - sha=0; - - if (st.hash==H256) sha=SHA256; - if (st.hash==H384) sha=SHA384; - if (st.hash==H512) sha=SHA512; - if (st.hash==0) - { - printf("Hash Function not supported\n"); - return 0; - } - - if (ECP_NIST256_VP_DSA(sha,&CAKEY,&H,&R,&S)!=0) - { - printf("***ECDSA Verification Failed\n"); - return 0; - } - else - printf("ECDSA Signature/Verification succeeded \n"); - } - - if (ca.type==RSA) - { - if (ca.curve!=2048) - { - printf("RSA bit size is not supported\n"); - return 0; - } - PK.e=65537; // assuming this! - RSA_2048_fromOctet(PK.n,&CAKEY); - - sha=0; - - if (st.hash==H256) sha=SHA256; - if (st.hash==H384) sha=SHA384; - if (st.hash==H512) sha=SHA512; - if (st.hash==0) - { - printf("Hash Function not supported\n"); - return 0; - } - PKCS15(sha,&H,&HP); - - RSA_2048_ENCRYPT(&PK,&SIG,&HH); - - if (OCT_comp(&HP,&HH)) - printf("RSA Signature/Verification succeeded \n"); - else + // search for Owner OID + len = getalen(SEQ, c->val, j); + if (len < 0) return 0; + j += skip(len); nj=j+len; + len = getalen(OID, c->val, j); + if (len < 0) return 0; + j += skip(len); + fin = j + len; // extract OID + if (len>FOID.max) return 0; + FOID.len = len; + for (i = 0; j < fin; j++) + FOID.val[i++] = c->val[j]; + if (OCT_comp(&FOID, SOID)) { - printf("***RSA Verification Failed\n"); - return 0; + // if its the right one return + *flen = nj-j; + return j; } + j = nj; // skip over this extension } + *flen = 0; /*****/ + return 0; +} - printf("\nNext check CA signature on cert, and extract public key\n"); - - OCT_frombase64(&IO,cert_b64); - printf("Example Cert= \n"); - OCT_output(&IO); - printf("\n"); - - st=X509_extract_cert_sig(&IO,&SIG); - - if (st.type==0) - { - printf("Unable to check cert signature\n"); - return 0; - } - - if (st.type==ECC) - { - OCT_chop(&SIG,&S,SIG.len/2); - OCT_copy(&R,&SIG); - printf("SIG= \n"); - OCT_output(&R); - - OCT_output(&S); - - printf("\n"); - } - - if (st.type==RSA) - { - printf("SIG= \n"); - OCT_output(&SIG); - printf("\n"); - } - - c=X509_extract_cert(&IO,&H); - - printf("Cert= \n"); - OCT_output(&H); - printf("\n"); - - printf("Subject Details\n"); - ic=X509_find_subject(&H); - c=X509_find_entity_property(&H,&ON,ic,&len); - print_out("owner=",&H,c,len); - c=X509_find_entity_property(&H,&CN,ic,&len); - print_out("country=",&H,c,len); - c=X509_find_entity_property(&H,&EN,ic,&len); - print_out("email=",&H,c,len); - printf("\n"); - - ic=X509_find_validity(&H); - c=X509_find_start_date(&H,ic); - print_date("start date= ",&H,c); - c=X509_find_expiry_date(&H,ic); - print_date("expiry date=",&H,c); - printf("\n"); - - pt=X509_extract_public_key(&H,&CERTKEY); - - if (pt.type==0) - { - printf("Not supported by library\n"); - return 0; - } - - if (pt.type==ECC) - { - printf("EXTRACTED ECC PUBLIC KEY= \n"); - OCT_output(&CERTKEY); - } - if (pt.type==RSA) - { - printf("EXTRACTED RSA PUBLIC KEY= \n"); - OCT_output(&CERTKEY); - } - - printf("\n"); - - /* Check CA signature */ +// return 1 if name found, else 0, where name is URL +// input cert, and pointer to SAN extension +// Takes wild-card into consideration +int X509_find_alt_name(octet *c,int start,char *name) +{ + int i,j,len,k,m,tlen,cmp,tag; - if (ca.type==ECC) + if (start==0) return 0; + j=start; + tlen = getalen(OCT, c->val, j); + if (tlen < 0) return 0; + j += skip(tlen); + + tlen = getalen(SEQ, c->val, j); + if (tlen < 0) return 0; + j += skip(tlen); + + for (k=j;jval[j]; tag&=0xff; + len = getalen(ANY, c->val, j); + if (len < 0) return 0; + j += skip(len); + if (tag!=DNS) + { // only interested in URLs + j+=len; + continue; } - - if (ECP_NIST256_VP_DSA(sha,&CAKEY,&H,&R,&S)!=0) - printf("***ECDSA Verification Failed\n"); - else - printf("ECDSA Signature/Verification succeeded \n"); - } - - if (ca.type==RSA) - { - printf("Checking CA's RSA Signature on Cert\n"); - PK.e=65537; // assuming this! - RSA_2048_fromOctet(PK.n,&CAKEY); - - sha=0; - - if (st.hash==H256) sha=SHA256; - if (st.hash==H384) sha=SHA384; - if (st.hash==H512) sha=SHA512; - if (st.hash==0) + cmp=1; m=0; + if (c->val[j]=='*') + { // wildcard + j++; len--; // skip over * + while (name[m]!='.' && name[m]!=0) + m++; + } + for (i=0;ival[j++]!=name[m++]) + cmp=0; } - PKCS15(sha,&H,&HP); - - RSA_2048_ENCRYPT(&PK,&SIG,&HH); - - if (OCT_comp(&HP,&HH)) - printf("RSA Signature/Verification succeeded \n"); - else - printf("***RSA Verification Failed\n"); - + if (name[m]!=0) cmp=0; + if (cmp) return 1; } - return 0; } -#endif From 875a40ff87fbf5f511e738a5708230df15cc65cd Mon Sep 17 00:00:00 2001 From: Jaromil Date: Tue, 21 Jan 2025 00:12:36 +0100 Subject: [PATCH 02/14] feat: first internal C api test for X509 --- test/api/testx509.c | 500 ++++++++++++++++++++++++++++++++++++++++++++ test/api/x509.bats | 35 ++++ 2 files changed, 535 insertions(+) create mode 100644 test/api/testx509.c create mode 100644 test/api/x509.bats diff --git a/test/api/testx509.c b/test/api/testx509.c new file mode 100644 index 000000000..c83fd24fc --- /dev/null +++ b/test/api/testx509.c @@ -0,0 +1,500 @@ +/* + * Copyright (c) 2012-2020 MIRACL UK Ltd. + * + * This file is part of MIRACL Core + * (see https://github.com/miracl/core). + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* CORE X.509 Functions */ + +// To run test program +// gcc -std=c99 x509.c core.a -o x509 + +#include +#include // for octet support only +#include + +// assumes library support for all of these +// #include "eddsa_Ed448.h" +// #include "eddsa_Ed25519.h" +// #include "ecdh_NIST256.h" +// #include "ecdh_NIST521.h" +#include "rsa_4096.h" +#include "rsa_2048.h" + +/* This simple driver program is hard-wired to support just one elliptic curve and one + RSA bit length. To change replace the text string NIST256 in the main program to + another curve and 2048 to some other value, where the curve and the RSA bit length + are suppported by the library. Of course a more elaborate program could support + muliple curves simultaneously */ + +#define CHOICE USE_ED448 + +/* test driver program */ +// Sample Certs. Uncomment one CA cert and one example cert. Note that CORE library must be built to support given curve. +// Sample Certs all created using OpenSSL - see http://blog.didierstevens.com/2008/12/30/howto-make-your-own-cert-with-openssl/ +// Note - SSL currently only supports NIST curves. Howevever version 1.1.0 of OpenSSL now supports C25519 + +#if CHOICE==USE_NIST256 + +// ** CA is RSA 2048-bit based - for use with NIST256 build of library - assumes use of SHA256 in Certs +// RSA 2048 Self-Signed CA cert +char ca_b64[] = "MIIDuzCCAqOgAwIBAgIJAP44jcM1MOROMA0GCSqGSIb3DQEBCwUAMHQxCzAJBgNVBAYTAklFMRAwDgYDVQQIDAdJcmVsYW5kMQ8wDQYDVQQHDAZEdWJsaW4xITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEfMB0GCSqGSIb3DQEJARYQbXNjb3R0QGluZGlnby5pZTAeFw0xNTExMjYwOTUwMzlaFw0yMDExMjUwOTUwMzlaMHQxCzAJBgNVBAYTAklFMRAwDgYDVQQIDAdJcmVsYW5kMQ8wDQYDVQQHDAZEdWJsaW4xITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEfMB0GCSqGSIb3DQEJARYQbXNjb3R0QGluZGlnby5pZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANUs7/nri9J8zw8rW8JVszXP0ZqeLoQJaq2X28ebm8x5VT3okr9rnBjFjpx0YKQCAFQf8iSOOYuNpDvtZ/YpsjPbk2rg5sLY9G0eUMqrTuZ7moPSxnrXS5evizjD9Z9HqaqeNEYD3sPouPg+lhU1oAUQjUTJVFhEr1x0EnSEYbbrWtY9ZDSuZv+d4NIeqqPOYFd1yZc+LYZyQbAAQqwRLNPZH/rnIykLa6I7w7mGT7H6SBz2O09BtgpTHhalL40ecXa4ZOEze0xwzlc+mEFIrnmdadg3vQrJt42RVbo3LN6RfDIqUZOMOtQW/53pUR1lIpCwVWJTiOpmSEIEqhhjFq0CAwEAAaNQME4wHQYDVR0OBBYEFJrz6LHeT6FcjRahpUC3hAMxKRTCMB8GA1UdIwQYMBaAFJrz6LHeT6FcjRahpUC3hAMxKRTCMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBADqkqCYVa3X8XO9Ufu6XIUoZafFPRjSeJXvEIWqlbm7ixJZ2FPOvf2eMc5RCZYigNKhsxru5Ojw0lPcpa8DDmEsdZDf7p0vlmf7T7xH9gtoInh4DzgI8HRHFc8R/z2/jLX7nlLoopKX5yp7F1gRACg0pd4tGpQ6EnBNcYZZghFH9UIRDmx+vDlwDCu8vyRPt35orrEiI4XGq/QkvxxAb5YWxQ4i06064ULfyCI7suu3KoobdM1aAaA8zhpOOBXKbq+Wi9IGFe/wiEMHLmfHdt9CBTjIWb//IHji4RT05kCmTVrx97pb7EHafuL3L10mM5cpTyBWKnb4kMFtx9yw+S2U="; +// an RSA 2048 CA-signed cert +char cert_b64[]="MIIDcjCCAloCAQEwDQYJKoZIhvcNAQELBQAwdDELMAkGA1UEBhMCSUUxEDAOBgNVBAgMB0lyZWxhbmQxDzANBgNVBAcMBkR1YmxpbjEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMR8wHQYJKoZIhvcNAQkBFhBtc2NvdHRAaW5kaWdvLmllMB4XDTE1MTEyNjEwMzQzMFoXDTE3MTEyNTEwMzQzMFowgYkxCzAJBgNVBAYTAklFMRAwDgYDVQQIDAdJcmVsYW5kMQ8wDQYDVQQHDAZEdWJsaW4xETAPBgNVBAoMCENlcnRpVm94MQ0wCwYDVQQLDARMYWJzMQ0wCwYDVQQDDARNSUtFMSYwJAYJKoZIhvcNAQkBFhdtaWtlLnNjb3R0QGNlcnRpdm94LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMIoxaQHFQzfyNChrw+3i7FjRFMHZ4zspkjkAcJW21LdBCqrxU+sdjyBoSFlrlafQOHshbrEP93AKX1bfaYbuV4fzq7OlRaLxaK+b+xrOJdewMI2WZ5OwEzj3onZATISogIoB6dTdzJ41NuxuMqQ/DqOnVrRA0SoIespbQhB8FGHBLw0hJATBzUk+bqOIt0HmnMp2EbYgtuG4lYINU/lD3Qt16SunUukWRLtxqJkioie+dkhP2zm+bOlSVmeQb4Wp8AI14OKkTfkdYC8qCxb5eabg90Q33rQUhNwRQHhHwopZwD/BgodasoSrPfwUlj0awh6y87eMGcik5Q/mjkCk5MCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAFrd7R/67ClkbLhpiX++6QTOa47siUAB9v+Qil9hZfhPNeeM589ixYkD4zH5pOK2B0ea+CXEKkanQ6lXx9KV86yS7fq6Yww7wO0diecusHd0+P82i46Tq0nm8nlsnAuhYoFRUGa2m2DkB1HSsB0ts8DjzFLySonFjSSLHDU0ox9/uFbJMzipy3ijAA4XM0N4jRrUfrmxpA7DOOsbEbGkvvB7VK9+s9PHE/4dJTwhSteplUnhxVFkkDo/JwaLx4/IEQRlCF3KEQ5s3AwRHnbrIjOY2yONxHBtJEp7QN5aOHruwvMNRNheCBPiQJyLitUsFGr4voANmobkrFgYtu0tRMQ=="; +// an ECC 256 CA-signed cert +// char cert_b64[] = "MIICojCCAYoCAQMwDQYJKoZIhvcNAQELBQAwdDELMAkGA1UEBhMCSUUxEDAOBgNVBAgMB0lyZWxhbmQxDzANBgNVBAcMBkR1YmxpbjEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMR8wHQYJKoZIhvcNAQkBFhBtc2NvdHRAaW5kaWdvLmllMB4XDTE1MTEyNjEzNDcyOVoXDTE3MTEyNTEzNDcyOVowgYQxCzAJBgNVBAYTAklFMRAwDgYDVQQIDAdJcmVsYW5kMQ8wDQYDVQQHDAZEdWJsaW4xETAPBgNVBAoMCENlcnRpdm94MQ0wCwYDVQQLDARMYWJzMQ8wDQYDVQQDDAZtc2NvdHQxHzAdBgkqhkiG9w0BCQEWEG1zY290dEBpbmRpZ28uaWUwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATO2iZiQZsXxzwBKnufKfZcsctNXZ4PmfJm638PmX9DQ3Xdb+nD5VxiOakNcB9xf5im8CriiOF5Z/7yPGyzUMbdMA0GCSqGSIb3DQEBCwUAA4IBAQAK5fMgGCCiPts8hMUZvYDpu8hd7qtPKPBc10QUccHb7PGrhqf/Ex2Gpj1aaURmx7SGZG0HX97LtkdW8KQpEoyaa60r7cjVA589TznxXKSGg5ggVoFJNpuZUm7VcolLjwIgTxtGbPzrvVMiZ4cl4PwFePXVKTl4f8XkOFX5gLmVSuCf729lEBmpx3IzqGmTjmnBixaApUElOKVeL7hiUKP3TqMUxZN+QNJBq4Mh9K9h4Sks2oneLwBwhMqQvpmcOb/7SucJn5N0IgJoGaMbfX0oCJJID1NSbagUSbFD1XciR2Ng9VtvnRP+htmEQ7jtww8phFdrWt5M5zPGOHUppqDx"; + +// ** CA is ECC 256 based - for use with NIST256 build of library +// ECC 256 Self-Signed CA cert +//char ca_b64[]="MIIB7TCCAZOgAwIBAgIJANp4nGS/VYj2MAoGCCqGSM49BAMCMFMxCzAJBgNVBAYTAklFMRAwDgYDVQQIDAdJcmVsYW5kMQ8wDQYDVQQHDAZEdWJsaW4xITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0xNTExMjYxMzI0MTBaFw0yMDExMjUxMzI0MTBaMFMxCzAJBgNVBAYTAklFMRAwDgYDVQQIDAdJcmVsYW5kMQ8wDQYDVQQHDAZEdWJsaW4xITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABPb6IjYNKyfbEtL1aafzW1jrn6ALn3PnGm7AyX+pcvwG0GKmb3Z/uHzhT4GysNE0/GB1n4Y/mrORQIm2X98rRs6jUDBOMB0GA1UdDgQWBBSfXUNkgJVklIhuXq4DCnVYhsdzwDAfBgNVHSMEGDAWgBSfXUNkgJVklIhuXq4DCnVYhsdzwDAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMCA0gAMEUCIQDrZJ1tshwTl/jabU2i49EOgbWe0ZgE3QZywJclf5IVwwIgVmz79AAf7e098lyrOKYAqbwjHVyMZGfmkNNGIuIhp/Q="; +// an ECC 256 CA-signed cert +//char cert_b64[]="MIIBvjCCAWQCAQEwCgYIKoZIzj0EAwIwUzELMAkGA1UEBhMCSUUxEDAOBgNVBAgMB0lyZWxhbmQxDzANBgNVBAcMBkR1YmxpbjEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMB4XDTE1MTEyNjEzMjc1N1oXDTE3MTEyNTEzMjc1N1owgYIxCzAJBgNVBAYTAklFMRAwDgYDVQQIDAdJcmVsYW5kMQ8wDQYDVQQHDAZEdWJsaW4xETAPBgNVBAoMCENlcnRpdm94MQ0wCwYDVQQLDARMYWJzMQ0wCwYDVQQDDARtaWtlMR8wHQYJKoZIhvcNAQkBFhBtc2NvdHRAaW5kaWdvLmllMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEY42H52TfWMLueKB1o2Sq8uKaKErbHJ2GRAxrnJdNxex0hxZF5FUx7664BbPUolKhpvKTnJxDq5/gMqXzpKgR6DAKBggqhkjOPQQDAgNIADBFAiEA0ew08Xg32g7BwheslVKwXo9XRRx4kygYha1+cn0tvaUCIEKCEwnosZlAckjcZt8aHN5zslE9K9Y7XxTErTstthKc"; +// an RSA 2048 CA-signed cert +// char cert_b64[]="MIICiDCCAi4CAQIwCgYIKoZIzj0EAwIwUzELMAkGA1UEBhMCSUUxEDAOBgNVBAgMB0lyZWxhbmQxDzANBgNVBAcMBkR1YmxpbjEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMB4XDTE1MTEyNjEzMzcwNVoXDTE3MTEyNTEzMzcwNVowgYExCzAJBgNVBAYTAklFMQ8wDQYDVQQIDAZJZWxhbmQxDzANBgNVBAcMBkR1YmxpbjERMA8GA1UECgwIQ2VydGl2b3gxDTALBgNVBAsMBExhYnMxDTALBgNVBAMMBE1pa2UxHzAdBgkqhkiG9w0BCQEWEG1zY290dEBpbmRpZ28uaWUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCjPBVwmPg8Gwx0+8xekmomptA0BDwS7NUfBetqDqNMNyji0bSe8LAfpciU7NW/HWfUE1lndCqSDDwnMJmwC5e3GAl/Bus+a+z8ruEhWGbn95xrHXFkOawbRlXuS7UcEQCvPr8KQHhNsg4cyV7Hn527CPUl27n+WN8/pANo01cTN/dQaK87naU0Mid09vktlMKSN0zyJOnc5CsaTLs+vCRKJ9sUL3d4IQIA2y7gvrTe+iY/QI26nqhGpNWYyFkAdy9PdHUEnDI6JsfF7jFh37yG7XEgDDA3asp/oi1T1+ZoASj2boL++opdqCzDndeWwzDWAWuvJ9wULd80ti6x737ZAgMBAAEwCgYIKoZIzj0EAwIDSAAwRQIgCDwgl98+9moBo+etaLt8MvB/z5Ti6i9neRTZkvoFl7YCIQDq//M3OB757fepErRzIQo3aFAFYjOooi6WdSqP3XqGIg=="; + +#endif + +#if CHOICE==USE_ED25519 + +// **CA is EDDSA Ed25519 based. Self-signed cert +char ca_b64[]= "MIIBRTCB+KADAgECAhNBrGyCRdfc0WyPpPd+LB8LEiK4MAUGAytlcDAZMRcwFQYDVQQDDA5NaWtlJ3Mgcm9vdCBDQTAeFw0yMzA1MDExNjAwMDlaFw0yNDA0MzAxNjAwMDlaMBkxFzAVBgNVBAMMDk1pa2UncyByb290IENBMCowBQYDK2VwAyEAh8YXRWdICdF8CcR1P0RCO4xD+s5i8Pzpq8KHid/TQaajUzBRMB0GA1UdDgQWBBQAS56sNYWyao4k6DS/M81i+wqjIzAfBgNVHSMEGDAWgBQAS56sNYWyao4k6DS/M81i+wqjIzAPBgNVHRMBAf8EBTADAQH/MAUGAytlcANBAJWIicxVB6ynhjjkJgNtcL/kmixU7l/V1j/N0AtenDgT+yrMhDW9n9JC+Ze5qpX3Eu3VkdkpN3G9anmBXp3LtAk="; +// EDDSA Ed25519 CA-signed Cert +char cert_b64[]="MIHdMIGQAgEBMAUGAytlcDAZMRcwFQYDVQQDDA5NaWtlJ3Mgcm9vdCBDQTAeFw0yMzA1MDExNjA1NDhaFw0yNDA0MzAxNjA1NDhaMB0xGzAZBgNVBAMMEk1pa2UncyBzZXJ2ZXIgY2VydDAqMAUGAytlcAMhANvhwg8UhnGMGt0bKoGt5IHkvHwyEwWj4GkLQ7XIqJeVMAUGAytlcANBAESWzTJbz/YVwLFrDKVqYxHc86YGjPa8lekAC8UciIKu9d1Xoko3ssfhNiXkYkl3M0yEnIkD2F2DfGKbt8LSmQE="; + +#endif + +#if CHOICE==USE_ED448 + +// **CA is EDDSA Ed448 based. Self-signed cert +char ca_b64[]= "MIIBkjCCARKgAwIBAgIUWnfFe8sR7CGIz3eN1CfyHdTz14kwBQYDK2VxMBkxFzAVBgNVBAMMDk1pa2UncyByb290IENBMB4XDTIzMDUwMTE2NDQxMloXDTI0MDQzMDE2NDQxMlowGTEXMBUGA1UEAwwOTWlrZSdzIHJvb3QgQ0EwQzAFBgMrZXEDOgACd4YB/lGYUck4KxQMJ+lshkHnBuigmwPALPQGARv26SK/EOi0DIMMpyp3oG+pnPpnqbqtDtesCYCjUzBRMB0GA1UdDgQWBBRygDXbx5h57oo1D91LitQV2PE2dzAfBgNVHSMEGDAWgBRygDXbx5h57oo1D91LitQV2PE2dzAPBgNVHRMBAf8EBTADAQH/MAUGAytlcQNzAI17NGvKrGAH5hKLUHC1+Qv5RvT4IKlWg5GnRGTccc5tCrimveoMbu2KTlNXaOHS8y/sZT1qddukAFLzR/1ehZqOnYLM7dwlgYdksAx0olo5+/MYfj3hw5noh1pMObnJREfTPTSg1gqFI+gObB1UoSsBAA=="; +// EDDSA Ed448 CA-signed Cert +char cert_b64[]="MIIBIzCBpAIBATAFBgMrZXEwGTEXMBUGA1UEAwwOTWlrZSdzIHJvb3QgQ0EwHhcNMjMwNTAxMTY0NjQzWhcNMjQwNDMwMTY0NjQzWjAYMRYwFAYDVQQDDA1NaWtlJ3Mgc2VydmVyMEMwBQYDK2VxAzoAgYh3CQP+EgId5/TZjAsuxh7Y9nPYtN5CYeN8vLjPuRqQncja3MyhRJaOrUEKSnBK+zYbkdXMQQwAMAUGAytlcQNzAPcm8DVSRZA1r0QqsSsHv6xBy1ASaoz4RFyelFMUD4f6ERMaxTzs0LKQHtcx5G9vqOxvQyCgkEu2AOcUQLtEXcoOSLH8fy0+5yEbbs6uPA1hi/oGpy580SR/5K5odY35fe1kwhz9YUvT4suTRHocnpcsAA=="; +#endif + + +char io[5000]; +octet IO = {0, sizeof(io), io}; + +#define MAXMODBYTES 72 +#define MAXFFLEN 16 + +char sig[MAXMODBYTES * MAXFFLEN]; +octet SIG = {0, sizeof(sig), sig}; + +char r[MAXMODBYTES]; +octet R = {0, sizeof(r), r}; + +char s[MAXMODBYTES]; +octet S = {0, sizeof(s), s}; + +char cakey[MAXMODBYTES * MAXFFLEN]; +octet CAKEY = {0, sizeof(cakey), cakey}; + +char certkey[MAXMODBYTES * MAXFFLEN]; +octet CERTKEY = {0, sizeof(certkey), certkey}; + +char h[5000]; +octet H = {0, sizeof(h), h}; + +char hh[5000]; +octet HH = {0, sizeof(hh), hh}; + +char hp[RFS_2048]; +octet HP = {0, sizeof(hp), hp}; + +void print_out(char *des, octet *c, int index, int len) +{ + int i; + printf("%s [", des); + for (i = 0; i < len; i++) + printf("%c", c->val[index + i]); + printf("]\n"); +} + +void print_date(char *des, octet *c, int index) +{ + int i = index; + printf("%s [", des); + if (i == 0) printf("]\n"); + else printf("20%c%c-%c%c-%c%c %c%c:%c%c:%c%c]\n", c->val[i], c->val[i + 1], c->val[i + 2], c->val[i + 3], c->val[i + 4], c->val[i + 5], c->val[i + 6], c->val[i + 7], c->val[i + 8], c->val[i + 9], c->val[i + 10], c->val[i + 11]); +} + +int main() +{ + int res, len, sha; + int c, ic; + rsa_public_key_2048 PK; + pktype st, ca, pt; + + printf("First check signature on self-signed cert and extract CA public key\n"); + OCT_frombase64(&IO, ca_b64); + printf("CA Self-Signed Cert= \n"); + OCT_output(&IO); + printf("\n"); + + st = X509_extract_cert_sig(&IO, &SIG); // returns signature type + + if (st.type == 0) + { + printf("Unable to extract cert signature\n"); + return 0; + } + + if (st.type == X509_ECC) + { + OCT_chop(&SIG, &S, SIG.len / 2); + OCT_copy(&R, &SIG); + printf("ECC SIG= \n"); + OCT_output(&R); + OCT_output(&S); + printf("\n"); + } + + if (st.type == X509_ECD) + { + printf("EDDSA SIG= \n"); + OCT_output(&SIG); + printf("\n"); + } + + if (st.type == X509_RSA) + { + printf("RSA SIG= \n"); + OCT_output(&SIG); + printf("\n"); + } + + if (st.hash == X509_H256) printf("Hashed with SHA256\n"); + if (st.hash == X509_H384) printf("Hashed with SHA384\n"); + if (st.hash == X509_H512) printf("Hashed with SHA512\n"); + +// Extract Cert from signed Cert + + c = X509_extract_cert(&IO, &H); + + printf("\nCert= \n"); + OCT_output(&H); + printf("\n"); + +// show some details + printf("Issuer Details\n"); + ic = X509_find_issuer(&H,&len); + c = X509_find_entity_property(&H, &X509_ON, ic, &len); + print_out("owner=", &H, c, len); + c = X509_find_entity_property(&H, &X509_CN, ic, &len); + print_out("country=", &H, c, len); + c = X509_find_entity_property(&H, &X509_EN, ic, &len); + print_out("email=", &H, c, len); + c = X509_find_entity_property(&H, &X509_MN, ic, &len); + print_out((char *)"Common Name=", &H, c, len); + printf("\n"); + + ca = X509_extract_public_key(&H, &CAKEY); + + if (ca.type == 0) + { + printf("Not supported by library\n"); + return 0; + } + if (ca.type != st.type) + { + printf("Not self-signed\n"); + } + + if (ca.type == X509_ECC) + { + printf("EXTRACTED ECC PUBLIC KEY= \n"); + OCT_output(&CAKEY); + } + if (ca.type == X509_RSA) + { + printf("EXTRACTED RSA PUBLIC KEY= \n"); + OCT_output(&CAKEY); + } + printf("\n"); + +// Cert is self-signed - so check signature + + printf("Checking Self-Signed Signature\n"); + if (ca.type == X509_ECC) + { + if (ca.curve != CHOICE) + { + printf("Curve is not supported\n"); + return 0; + } + // res = ECP_NIST256_PUBLIC_KEY_VALIDATE(&CAKEY); + // if (res != 0) + // { + // printf("ECP Public Key is invalid!\n"); + // return 0; + // } + // else printf("ECP Public Key is Valid\n"); + + sha = 0; + + if (st.hash == X509_H256) sha = SHA256; + if (st.hash == X509_H384) sha = SHA384; + if (st.hash == X509_H512) sha = SHA512; + if (sha == 0) + { + printf("Hash Function not supported\n"); + return 0; + } + + // if (ECP_NIST256_VP_DSA(sha, &CAKEY, &H, &R, &S) != 0) + // { + // printf("***ECDSA Verification Failed\n"); + // return 0; + // } + // else + // printf("ECDSA Signature/Verification succeeded \n"); + } + + if (ca.type == X509_ECD) + { + if (ca.curve != CHOICE) + { + printf("Curve is not supported %d\n",ca.curve); + return 0; + } + // if (ca.curve == USE_ED25519) + // { + // if (!EDDSA_Ed25519_VERIFY(false,&CAKEY,NULL,&H,&SIG)) + // { + // printf("***EDDSA Verification Failed\n"); + // return 0; + // } + // else + // printf("EDDSA Signature/Verification succeeded \n"); + // } + // if (ca.curve == USE_ED448) + // { + // if (!EDDSA_Ed448_VERIFY(false,&CAKEY,NULL,&H,&SIG)) + // { + // printf("***EDDSA Verification Failed %d\n",SIG.len); + // return 0; + // } + // else + // printf("EDDSA Signature/Verification succeeded \n"); + // } + } + + if (ca.type == X509_RSA) + { + if (ca.curve != 2048) + { + printf("RSA bit size is not supported\n"); + return 0; + } + PK.e = 65537; // assuming this! + RSA_2048_fromOctet(PK.n, &CAKEY); + + sha = 0; + + if (st.hash == X509_H256) sha = SHA256; + if (st.hash == X509_H384) sha = SHA384; + if (st.hash == X509_H512) sha = SHA512; + if (sha == 0) + { + printf("Hash Function not supported\n"); + return 0; + } + PKCS15(sha, &H, &HP); + + RSA_2048_ENCRYPT(&PK, &SIG, &HH); + + if (OCT_comp(&HP, &HH)) + printf("RSA Signature/Verification succeeded \n"); + else + { + printf("***RSA Verification Failed\n"); + return 0; + } + } + + printf("\nNext check CA signature on cert, and extract public key\n"); + + OCT_frombase64(&IO, cert_b64); + printf("Example Cert= \n"); + OCT_output(&IO); + printf("\n"); + + st = X509_extract_cert_sig(&IO, &SIG); + + if (st.type == 0) + { + printf("Unable to check cert signature\n"); + return 0; + } + + if (st.type == X509_ECC) + { + OCT_chop(&SIG, &S, SIG.len / 2); + OCT_copy(&R, &SIG); + printf("SIG= \n"); + OCT_output(&R); + + OCT_output(&S); + + printf("\n"); + } + + if (st.type == X509_ECD) + { + printf("SIG= \n"); + OCT_output(&SIG); + printf("\n"); + } + + if (st.type == X509_RSA) + { + printf("SIG= \n"); + OCT_output(&SIG); + printf("\n"); + } + + c = X509_extract_cert(&IO, &H); + + printf("Cert= \n"); + OCT_output(&H); + printf("\n"); + + printf("Subject Details\n"); + ic = X509_find_subject(&H,&len); + c = X509_find_entity_property(&H, &X509_ON, ic, &len); + print_out("owner=", &H, c, len); + c = X509_find_entity_property(&H, &X509_CN, ic, &len); + print_out("country=", &H, c, len); + c = X509_find_entity_property(&H, &X509_EN, ic, &len); + print_out("email=", &H, c, len); + c = X509_find_entity_property(&H, &X509_MN, ic, &len); + print_out((char *)"Common Name=", &H, c, len); + printf("\n"); + + ic = X509_find_validity(&H); + c = X509_find_start_date(&H, ic); + print_date("start date= ", &H, c); + c = X509_find_expiry_date(&H, ic); + print_date("expiry date=", &H, c); + printf("\n"); + + pt = X509_extract_public_key(&H, &CERTKEY); + + if (pt.type == 0) + { + printf("Not supported by library\n"); + return 0; + } + + if (pt.type == X509_ECC) + { + printf("EXTRACTED ECDSA PUBLIC KEY= \n"); + OCT_output(&CERTKEY); + } + if (pt.type == X509_ECD) + { + printf("EXTRACTED EDDSA PUBLIC KEY= \n"); + OCT_output(&CERTKEY); + } + if (pt.type == X509_RSA) + { + printf("EXTRACTED RSA PUBLIC KEY= \n"); + OCT_output(&CERTKEY); + } + + printf("\n"); + + /* Check CA signature */ + + // if (ca.type == X509_ECC) + // { + // // printf("Checking CA's ECC Signature on Cert\n"); + // // res = ECP_NIST256_PUBLIC_KEY_VALIDATE(&CAKEY); + // // if (res != 0) + // // printf("ECP Public Key is invalid!\n"); + // // else printf("ECP Public Key is Valid\n"); + + // sha = 0; + + // if (st.hash == X509_H256) sha = SHA256; + // if (st.hash == X509_H384) sha = SHA384; + // if (st.hash == X509_H512) sha = SHA512; + // if (sha == 0) + // { + // printf("Hash Function not supported\n"); + // return 0; + // } + + // if (ECP_NIST256_VP_DSA(sha, &CAKEY, &H, &R, &S) != 0) + // printf("***ECDSA Verification Failed\n"); + // else + // printf("ECDSA Signature/Verification succeeded \n"); + // } + + // if (ca.type == X509_ECD) + // { + // printf("Checking CA's EDDSA Signature on Cert\n"); + // if (ca.curve == USE_ED25519) + // { + // if (!EDDSA_Ed25519_VERIFY(false,&CAKEY,NULL,&H,&SIG)) + // { + // printf("***EDDSA Verification Failed\n"); + // return 0; + // } + // else + // printf("EDDSA Signature/Verification succeeded \n"); + // } + // if (ca.curve == USE_ED448) + // { + // if (!EDDSA_Ed448_VERIFY(false,&CAKEY,NULL,&H,&SIG)) + // { + // printf("***EDDSA Verification Failed\n"); + // return 0; + // } + // else + // printf("EDDSA Signature/Verification succeeded \n"); + // } + // } + + if (ca.type == X509_RSA) + { + printf("Checking CA's RSA Signature on Cert\n"); + PK.e = 65537; // assuming this! + RSA_2048_fromOctet(PK.n, &CAKEY); + + sha = 0; + + if (st.hash == X509_H256) sha = SHA256; + if (st.hash == X509_H384) sha = SHA384; + if (st.hash == X509_H512) sha = SHA512; + if (sha == 0) + { + printf("Hash Function not supported\n"); + return 0; + } + PKCS15(sha, &H, &HP); + + RSA_2048_ENCRYPT(&PK, &SIG, &HH); + + if (OCT_comp(&HP, &HH)) + printf("RSA Signature/Verification succeeded \n"); + else + printf("***RSA Verification Failed\n"); + } + + return 0; +} diff --git a/test/api/x509.bats b/test/api/x509.bats new file mode 100644 index 000000000..13790a3c7 --- /dev/null +++ b/test/api/x509.bats @@ -0,0 +1,35 @@ +# setup paths for BATS test units +setup() { + bats_require_minimum_version 1.5.0 + T="$BATS_TEST_DIRNAME" + TR=`cd "$T"/.. && pwd` + R=`cd "$TR"/.. && pwd` + TMP="$BATS_TEST_TMPDIR" + load "$TR"/test_helper/bats-support/load + load "$TR"/test_helper/bats-assert/load + load "$TR"/test_helper/bats-file/load + ZTMP="$BATS_FILE_TMPDIR" + cd $ZTMP +} + + +save() { + >&3 echo " 💾 $1" + export output=`cat $ZTMP/$1` +} + +@test "X509 AMCL LIB :: Compile test" { + AMCL="${R}/lib/milagro-crypto-c/build/lib" + LDADD="${AMCL}/libamcl_core.a ${AMCL}/libamcl_x509.a" + LDADD="$LDADD ${AMCL}/libamcl_rsa_2048.a ${AMCL}/libamcl_rsa_4096.a" + CFLAGS="$CFLAGS -I$R/src -I$R/lib/milagro-crypto-c/include" + CFLAGS="$CFLAGS -I$R/lib/milagro-crypto-c/build/include" + gcc -c $T/testx509.c $CFLAGS + gcc ${CFLAGS} -ggdb -o x509 testx509.o ${LDADD} +} + +@test "X509 AMCL LIB :: Run test" { + LD_LIBRARY_PATH=$R ./x509 > test_x509 + save test_x509 + +} From a1fdf0337b81711a5247b95d0ccd060a9fdeb767 Mon Sep 17 00:00:00 2001 From: Jaromil Date: Tue, 21 Jan 2025 10:55:00 +0100 Subject: [PATCH 03/14] test: read self-signed EC-P256 certificate from didroom --- test/api/x509.bats | 17 +++-- test/api/x509_didroom.c | 133 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 145 insertions(+), 5 deletions(-) create mode 100644 test/api/x509_didroom.c diff --git a/test/api/x509.bats b/test/api/x509.bats index 13790a3c7..bb39dfe23 100644 --- a/test/api/x509.bats +++ b/test/api/x509.bats @@ -19,17 +19,24 @@ save() { } @test "X509 AMCL LIB :: Compile test" { - AMCL="${R}/lib/milagro-crypto-c/build/lib" + AMCL="${R}/lib/milagro-crypto-c/build/lib" LDADD="${AMCL}/libamcl_core.a ${AMCL}/libamcl_x509.a" LDADD="$LDADD ${AMCL}/libamcl_rsa_2048.a ${AMCL}/libamcl_rsa_4096.a" CFLAGS="$CFLAGS -I$R/src -I$R/lib/milagro-crypto-c/include" - CFLAGS="$CFLAGS -I$R/lib/milagro-crypto-c/build/include" - gcc -c $T/testx509.c $CFLAGS - gcc ${CFLAGS} -ggdb -o x509 testx509.o ${LDADD} + CFLAGS="$CFLAGS -I$R/lib/milagro-crypto-c/build/include" + CFLAGS="$CFLAGS -fsanitize=address -fsanitize=undefined -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow -fsanitize=leak" + gcc ${CFLAGS} -ggdb -o x509 $T/testx509.c ${LDADD} + gcc ${CFLAGS} -ggdb -o x509_didroom $T/x509_didroom.c ${LDADD} } -@test "X509 AMCL LIB :: Run test" { +@test "X509 AMCL LIB :: Run test for RSA" { LD_LIBRARY_PATH=$R ./x509 > test_x509 save test_x509 + >&3 cat test_x509 +} +@test "X509 Zenroom LIB :: Run test for P256 Didroom" { + LD_LIBRARY_PATH=$R ./x509_didroom > test_x509_didroom + save test_x509_didroom + >&3 cat test_x509_didroom } diff --git a/test/api/x509_didroom.c b/test/api/x509_didroom.c new file mode 100644 index 000000000..7ef67087b --- /dev/null +++ b/test/api/x509_didroom.c @@ -0,0 +1,133 @@ +// test x509 with P256 lib from zenroom + +#include +#include // for octet support only +#include + + // "-----BEGIN CERTIFICATE-----" +char didroom_selfsign_p256[]= + "MIIB5zCCAY2gAwIBAgIBATAKBggqhkjOPQQDAjAgMR4wHAYDVQQDDBVEaWRyb29t" + "IC0gbWF0dGVvIPCfm7gwHhcNMjUwMTIwMDg1ODEwWhcNMjYwMTIxMDg1ODEwWjAg" + "MR4wHAYDVQQDDBVEaWRyb29tIC0gbWF0dGVvIPCfm7gwWTATBgcqhkjOPQIBBggq" + "hkjOPQMBBwNCAATUtxD9sLQNnsl2eLtW58u7RI5e6CB9nHA3aGAMZrI6hZBzU04K" + "oxyteoM/f5RbCTFjcGFby66D6xyciBDFFkXno4G3MIG0MBIGA1UdEwEB/wQIMAYB" + "Af8CAQIwHAYDVR0lAQH/BBIwEAYGKgMEBQYHBgZTBAUGBwgwDgYDVR0PAQH/BAQD" + "AgEGMB0GA1UdDgQWBBTuz5prI2WpFQJjXzyTu7ZUhj0/QjBRBgNVHREESjBIhkZk" + "aWQ6ZHluZTpzYW5kYm94LnNpZ25yb29tOjRLRXltV2dMRFVmMUxOY2tleFk5NmRm" + "S3o1dkg3OWRpRGVrZ0xNUjlGV3BIMAoGCCqGSM49BAMCA0gAMEUCIQCVetesj1HI" + "U43l7wzHuj+lX5ZJA9P019HuGazQA3RTVgIgSHXU5Brj7rSaBBUdY8uBdKPE/h0Z" + "oBqKuv/u9Qf8mdM="; +// "-----END CERTIFICATE-----"; +// "-----BEGIN EC PRIVATE KEY-----" +char didroom_privkey_p256[]= + "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgB648VWj7/K+tQ4eZ" + "82blPBV4jwi1qSCWWIyT7xf3J0OhRANCAATUtxD9sLQNnsl2eLtW58u7RI5e6CB9" + "nHA3aGAMZrI6hZBzU04KoxyteoM/f5RbCTFjcGFby66D6xyciBDFFkXn"; +// "-----END EC PRIVATE KEY-----"; + +char io[5000]; +octet IO = {0, sizeof(io), io}; + +#define MAXMODBYTES 72 +#define MAXFFLEN 16 +char sig[MAXMODBYTES * MAXFFLEN]; +octet SIG = {0, sizeof(sig), sig}; +char r[MAXMODBYTES]; +octet R = {0, sizeof(r), r}; +char s[MAXMODBYTES]; +octet S = {0, sizeof(s), s}; +char cakey[MAXMODBYTES * MAXFFLEN]; +octet CAKEY = {0, sizeof(cakey), cakey}; +char certkey[MAXMODBYTES * MAXFFLEN]; +octet CERTKEY = {0, sizeof(certkey), certkey}; + +// extracted cert +char h[5000]; +octet H = {0, sizeof(h), h}; + +char hh[5000]; +octet HH = {0, sizeof(hh), hh}; + +void print_out(char *des, octet *c, int index, int len) +{ + int i; + printf("%s [", des); + for (i = 0; i < len; i++) + printf("%c", c->val[index + i]); + printf("]\n"); +} + +void print_date(char *des, octet *c, int index) +{ + int i = index; + printf("%s [", des); + if (i == 0) printf("]\n"); + else printf("20%c%c-%c%c-%c%c %c%c:%c%c:%c%c]\n", c->val[i], c->val[i + 1], c->val[i + 2], c->val[i + 3], c->val[i + 4], c->val[i + 5], c->val[i + 6], c->val[i + 7], c->val[i + 8], c->val[i + 9], c->val[i + 10], c->val[i + 11]); +} + +int main(int argc, char **argv) { + int res, len, sha; + int c, ic; + pktype st, ca, pt; + + OCT_frombase64(&IO, didroom_selfsign_p256); + printf("CA Self-Signed Cert= \n"); + OCT_output(&IO); + printf("\n"); + + // extract R and S from P256 sig + st = X509_extract_cert_sig(&IO, &SIG); + + if (st.type == X509_ECC) { + OCT_chop(&SIG, &S, SIG.len / 2); + OCT_copy(&R, &SIG); + printf("ECC SIG= \n"); + OCT_output(&R); + OCT_output(&S); + printf("\n"); + } else { + printf("Unable to extract cert signature type: %i\n",st.type); + return 0; + } + if (st.hash == X509_H256) printf("Hashed with SHA256\n"); + if (st.hash == X509_H384) printf("Hashed with SHA384\n"); + if (st.hash == X509_H512) printf("Hashed with SHA512\n"); + + c = X509_extract_cert(&IO, &H); + printf("\nCert= \n"); + OCT_output(&H); + printf("\n"); +// show some details + printf("Issuer Details\n"); + ic = X509_find_issuer(&H,&len); + c = X509_find_entity_property(&H, &X509_ON, ic, &len); + print_out("owner=", &H, c, len); + c = X509_find_entity_property(&H, &X509_CN, ic, &len); + print_out("country=", &H, c, len); + c = X509_find_entity_property(&H, &X509_EN, ic, &len); + print_out("email=", &H, c, len); + c = X509_find_entity_property(&H, &X509_MN, ic, &len); + print_out((char *)"Common Name=", &H, c, len); + printf("\n"); + + ca = X509_extract_public_key(&H, &CAKEY); + if (ca.type != st.type) { + printf("Certificate is not self-signed\n"); + } + if (ca.type == 0) { + printf("CA Type 0 not supported\n"); + return 0; + } else { + printf("CA type: %u\n",ca.type); + } + printf("EXTRACTED PUBLIC KEY= \n"); + OCT_output(&CAKEY); + + ic = X509_find_validity(&H); + c = X509_find_start_date(&H, ic); + print_date("start date= ", &H, c); + c = X509_find_expiry_date(&H, ic); + print_date("expiry date=", &H, c); + printf("\n"); + +} From 6307dfe7cf1923682eea229630802081a1ae0992 Mon Sep 17 00:00:00 2001 From: Jaromil Date: Tue, 21 Jan 2025 12:34:21 +0100 Subject: [PATCH 04/14] test: raw quick cert extraction on a pq cert made with openssl+oqs --- test/api/x509.bats | 8 ++ test/api/x509_postquantum.c | 143 ++++++++++++++++++++++++++++++++++++ 2 files changed, 151 insertions(+) create mode 100644 test/api/x509_postquantum.c diff --git a/test/api/x509.bats b/test/api/x509.bats index bb39dfe23..618d7a10e 100644 --- a/test/api/x509.bats +++ b/test/api/x509.bats @@ -27,6 +27,8 @@ save() { CFLAGS="$CFLAGS -fsanitize=address -fsanitize=undefined -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow -fsanitize=leak" gcc ${CFLAGS} -ggdb -o x509 $T/testx509.c ${LDADD} gcc ${CFLAGS} -ggdb -o x509_didroom $T/x509_didroom.c ${LDADD} + gcc ${CFLAGS} -ggdb -o x509_postquantum $T/x509_postquantum.c ${LDADD} + } @test "X509 AMCL LIB :: Run test for RSA" { @@ -40,3 +42,9 @@ save() { save test_x509_didroom >&3 cat test_x509_didroom } + +@test "X509 Zenroom LIB :: Run test for Post-Quantum X509" { + LD_LIBRARY_PATH=$R ./x509_postquantum > test_x509_postquantum + save test_x509_postquantum + >&3 cat test_x509_postquantum +} diff --git a/test/api/x509_postquantum.c b/test/api/x509_postquantum.c new file mode 100644 index 000000000..0b67dac97 --- /dev/null +++ b/test/api/x509_postquantum.c @@ -0,0 +1,143 @@ +// test x509 for post-quantum safe zenroom + +#include +#include // for octet support only +#include + + // "-----BEGIN CERTIFICATE-----" +char selfsign_pq[]= +"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" +"AAAAAAAAAAAAAAAPHis8"; + + +char io[5000*2]; +octet IO = {0, sizeof(io), io}; +// extracted cert +char h[5000*2]; +octet H = {0, sizeof(h), h}; + +#define MAXMODBYTES 6000 +#define MAXFFLEN 6000 +char sig[MAXMODBYTES * MAXFFLEN]; +octet SIG = {0, sizeof(sig), sig}; +char r[MAXMODBYTES]; +octet R = {0, sizeof(r), r}; +char s[MAXMODBYTES]; +octet S = {0, sizeof(s), s}; + +void print_out(char *des, octet *c, int index, int len) +{ + int i; + printf("%s [", des); + for (i = 0; i < len; i++) + printf("%c", c->val[index + i]); + printf("]\n"); +} + +void print_date(char *des, octet *c, int index) +{ + int i = index; + printf("%s [", des); + if (i == 0) printf("]\n"); + else printf("20%c%c-%c%c-%c%c %c%c:%c%c:%c%c]\n", c->val[i], c->val[i + 1], c->val[i + 2], c->val[i + 3], c->val[i + 4], c->val[i + 5], c->val[i + 6], c->val[i + 7], c->val[i + 8], c->val[i + 9], c->val[i + 10], c->val[i + 11]); +} + + +int main(int argc, char **argv) { + int res, len, sha; + int c, ic; + pktype st, ca, pt; + + OCT_frombase64(&IO, selfsign_pq); + printf("CA Self-Signed Cert= \n"); + OCT_output(&IO); + printf("\n"); + + // extract R and S from P256 sig + st = X509_extract_cert_sig(&IO, &SIG); + printf("type: %u\n",st.type); + printf("hash: %u\n",st.hash); + printf("curve: %u\n",st.curve); + OCT_output(&SIG); + printf("\n"); +} From be9bc3218d52fd3f0454b49d61d1f67bd8973e70 Mon Sep 17 00:00:00 2001 From: Jaromil Date: Tue, 21 Jan 2025 18:36:16 +0100 Subject: [PATCH 05/14] feat: x509 primitives in lua for zenroom starting point to develop zencode functions, this simple api has a few sanity checks so relies on a well checked zencode implementation. the api provides a pem decoder and extraction tools (pem->cert->* pem->sig) lua test coverage for both pk and sk verification --- build/init.mk | 2 +- src/lua_modules.c | 3 + src/zen_p256.c | 2 + src/zen_x509.c | 159 +++++++++++++++++++++++++++++++++++++++++++ test/lua/crypto.bats | 1 + test/lua/x509.lua | 41 +++++++++++ 6 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 src/zen_x509.c create mode 100644 test/lua/x509.lua diff --git a/build/init.mk b/build/init.mk index d8802bc01..592e5491d 100644 --- a/build/init.mk +++ b/build/init.mk @@ -11,7 +11,7 @@ ZEN_SOURCES := \ src/zen_io.o src/zen_parse.o src/zen_config.o \ src/zen_octet.o src/zen_ecp.o src/zen_ecp2.o src/zen_big.o \ src/zen_fp12.o src/zen_random.o src/zen_hash.o \ - src/zen_ecdh_factory.o src/zen_ecdh.o \ + src/zen_ecdh_factory.o src/zen_ecdh.o src/zen_x509.o \ src/zen_aes.o src/zen_qp.o src/zen_ed.o src/zen_float.o src/zen_time.o \ src/api_hash.o src/api_sign.o src/randombytes.o \ src/cortex_m.o src/p256-m.o src/zen_p256.o src/zen_rsa.o src/zen_bbs.o diff --git a/src/lua_modules.c b/src/lua_modules.c index a92b6d4e9..4124d8389 100644 --- a/src/lua_modules.c +++ b/src/lua_modules.c @@ -59,6 +59,7 @@ extern int luaopen_time(lua_State *L); extern int luaopen_qp(lua_State *L); extern int luaopen_ed(lua_State *L); extern int luaopen_p256(lua_State *L); +extern int luaopen_x509(lua_State *L); // really loaded in lib/lua54/linit.c // always align here for correct reference @@ -193,6 +194,8 @@ int zen_require(lua_State *L) { luaL_requiref(L, s, luaopen_p256, 1); } else if(strcasecmp(s, "bbs") ==0) { luaL_requiref(L, s, luaopen_bbs, 1); } + else if(strcasecmp(s, "x509") ==0) { + luaL_requiref(L, s, luaopen_x509, 1); } else { // shall we bail out and abort execution here? warning(L, "required extension not found: %s", s); diff --git a/src/zen_p256.c b/src/zen_p256.c index d89e1048b..1a0101568 100644 --- a/src/zen_p256.c +++ b/src/zen_p256.c @@ -93,12 +93,14 @@ static int p256_pubgen(lua_State *L) static int p256_session(lua_State *L) { BEGIN(); + // TODO: is there a KEM session function in our p256 lib? END(1); } static int p256_pubcheck(lua_State *L) { BEGIN(); + // TODO: here make a check if public key is valid and return bool END(1); } diff --git a/src/zen_x509.c b/src/zen_x509.c new file mode 100644 index 000000000..c309c4d33 --- /dev/null +++ b/src/zen_x509.c @@ -0,0 +1,159 @@ +/* This file is part of Zenroom (https://zenroom.dyne.org) + * + * Copyright (C) 2025 Dyne.org foundation + * designed, written and maintained by Denis Roio + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#define BUF_SIZE 8192 +#define SAFE(x) if(!x) { failed_msg="NULL var"; goto end; } + +static int pem_to_base64(lua_State *L) { + BEGIN(); + char *failed_msg = NULL; + const char *begin_marker = "-----BEGIN"; + const char *end_marker = "-----END"; + const char *in = lua_tostring(L, 1); + luaL_argcheck(L, in != NULL, 1, "string argument expected"); + char *dst = calloc(strlen(in)+2,1); + char *output = dst; + const char *begin = strstr(in, begin_marker); + const char *end = strstr(in, end_marker); + + if (begin && end) { + const char *base64_start = strchr(begin, '\n'); + if (base64_start) { + base64_start++; + const char *base64_end = strstr(base64_start, end_marker); + if (base64_end) { + while (base64_start < base64_end) { + if (*base64_start != '\n' && *base64_start != '\r') { + *output++ = *base64_start; + } + base64_start++; + } + *output = '\0'; // Null-terminate the output string + } + } + } + end: + lua_pushlstring(L, dst, strlen(dst)); + free(dst); + if(failed_msg) { + THROW(failed_msg); + } + END(1); + +} + +static int extract_cert(lua_State *L) { + BEGIN(); + char *failed_msg = NULL; + const octet *in = o_arg(L, 1); SAFE(in); + octet *c = o_new(L,BUF_SIZE); SAFE(c); + X509_extract_cert((octet*)in, c); + end: + o_free(L,in); + if(failed_msg) { + THROW(failed_msg); + } + END(1); +} + +static int extract_cert_sig(lua_State *L) { + BEGIN(); + pktype st; + char *failed_msg = NULL; + const octet *in = o_arg(L, 1); SAFE(in); + octet *sig = o_new(L,BUF_SIZE); SAFE(sig); + st = X509_extract_cert_sig((octet*)in, sig); + func(L,"SIG type: %u",st.type); + end: + o_free(L,in); + if(failed_msg) { + THROW(failed_msg); + } + END(1); +} + +static int extract_pubkey(lua_State *L) { + BEGIN(); + pktype ca; + char *failed_msg = NULL; + const octet *in = o_arg(L, 1); SAFE(in); + octet *raw = o_alloc(L,BUF_SIZE); SAFE(raw); + ca = X509_extract_public_key((octet*)in, raw); + octet *pk = o_new(L,raw->len); SAFE(pk); + // shave the leftmost byte on P256 ( 0x04 ) + memcpy(pk->val,raw->val+1,raw->len-1); + pk->len = raw->len-1; + o_free(L,raw); + func(L,"CA type: %u",ca.type); + // TODO: ca.type switch/case and return string and hash + // lua_pushlstring(L, ca.type..., strlen(ca.type)); + end: + o_free(L,in); + if(failed_msg) { + THROW(failed_msg); + } + END(1); +} + +static int extract_seckey(lua_State *L) { + BEGIN(); + pktype sk_t; + char *failed_msg = NULL; + const octet *in = o_arg(L, 1); SAFE(in); + octet *sk = o_new(L,in->len); SAFE(sk); + sk_t = X509_extract_private_key((octet*)in,sk); + func(L,"SK type: %u",sk_t.type); +end: + o_free(L,in); + if(failed_msg) { + THROW(failed_msg); + } + END(1); +} + +int luaopen_x509(lua_State *L) { + (void)L; + const struct luaL_Reg x509_class[] = { + {"pem_to_base64", pem_to_base64}, + {"extract_cert", extract_cert}, + {"extract_cert_sig", extract_cert_sig}, + {"extract_pubkey", extract_pubkey}, + {"extract_seckey", extract_seckey}, + {NULL,NULL} + }; + const struct luaL_Reg x509_methods[] = { + {NULL,NULL} + }; + zen_add_class(L, "x509", x509_class, x509_methods); + return 1; +} diff --git a/test/lua/crypto.bats b/test/lua/crypto.bats index c7185ecc6..a100104b0 100644 --- a/test/lua/crypto.bats +++ b/test/lua/crypto.bats @@ -7,6 +7,7 @@ load ../bats_setup Z hash.lua Z ecdh.lua Z ecdsa_p256.lua + Z x509.lua Z dh_session.lua Z ecp_generic.lua Z elgamal.lua diff --git a/test/lua/x509.lua b/test/lua/x509.lua new file mode 100644 index 000000000..cf0781151 --- /dev/null +++ b/test/lua/x509.lua @@ -0,0 +1,41 @@ +CERT = [[ +-----BEGIN CERTIFICATE----- +MIIB5zCCAY2gAwIBAgIBATAKBggqhkjOPQQDAjAgMR4wHAYDVQQDDBVEaWRyb29t +IC0gbWF0dGVvIPCfm7gwHhcNMjUwMTIwMDg1ODEwWhcNMjYwMTIxMDg1ODEwWjAg +MR4wHAYDVQQDDBVEaWRyb29tIC0gbWF0dGVvIPCfm7gwWTATBgcqhkjOPQIBBggq +hkjOPQMBBwNCAATUtxD9sLQNnsl2eLtW58u7RI5e6CB9nHA3aGAMZrI6hZBzU04K +oxyteoM/f5RbCTFjcGFby66D6xyciBDFFkXno4G3MIG0MBIGA1UdEwEB/wQIMAYB +Af8CAQIwHAYDVR0lAQH/BBIwEAYGKgMEBQYHBgZTBAUGBwgwDgYDVR0PAQH/BAQD +AgEGMB0GA1UdDgQWBBTuz5prI2WpFQJjXzyTu7ZUhj0/QjBRBgNVHREESjBIhkZk +aWQ6ZHluZTpzYW5kYm94LnNpZ25yb29tOjRLRXltV2dMRFVmMUxOY2tleFk5NmRm +S3o1dkg3OWRpRGVrZ0xNUjlGV3BIMAoGCCqGSM49BAMCA0gAMEUCIQCVetesj1HI +U43l7wzHuj+lX5ZJA9P019HuGazQA3RTVgIgSHXU5Brj7rSaBBUdY8uBdKPE/h0Z +oBqKuv/u9Qf8mdM= +-----END CERTIFICATE----- +]] + +KEY = [[ +-----BEGIN EC PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgB648VWj7/K+tQ4eZ +82blPBV4jwi1qSCWWIyT7xf3J0OhRANCAATUtxD9sLQNnsl2eLtW58u7RI5e6CB9 +nHA3aGAMZrI6hZBzU04KoxyteoM/f5RbCTFjcGFby66D6xyciBDFFkXn +-----END EC PRIVATE KEY----- +]] + +x509 = require'x509' +P256 = require('es256') + +pem = OCTET.from_base64(x509.pem_to_base64(CERT)) +I.print({PEM=pem}) +cert = x509.extract_cert(pem) +sig = x509.extract_cert_sig(pem) +pk = x509.extract_pubkey(cert) +I.print({cert=cert, sig=sig, pubkey=pk}) + +assert( P256.verify(pk,cert,sig) ) + +key = I.spy( x509.extract_seckey( + OCTET.from_base64(x509.pem_to_base64(KEY)) +)) + +assert( P256.pubgen(key) == pk) From edaf160923ac232f2f9368c7013652ba056a10ab Mon Sep 17 00:00:00 2001 From: Jaromil Date: Thu, 23 Jan 2025 19:20:33 +0100 Subject: [PATCH 06/14] feat: also extract issuer information and validity dates --- src/zen_x509.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++- test/lua/x509.lua | 11 ++++-- 2 files changed, 93 insertions(+), 4 deletions(-) diff --git a/src/zen_x509.c b/src/zen_x509.c index c309c4d33..833863157 100644 --- a/src/zen_x509.c +++ b/src/zen_x509.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include @@ -141,6 +140,89 @@ static int extract_seckey(lua_State *L) { END(1); } +static void push_entity_property(lua_State *L, const octet *H, int c, int len) { + char tmp[2048]; + snprintf(tmp,len,"%s",&H->val[c]); + lua_pushstring(L,tmp); +} + +static void push_date(lua_State *L, const octet *c, int i) { + char tmp[24]; + snprintf(tmp,20,"20%c%c-%c%c-%c%c %c%c:%c%c:%c%c", + c->val[i], c->val[i + 1], c->val[i + 2], + c->val[i + 3], c->val[i + 4], c->val[i + 5], + c->val[i + 6], c->val[i + 7], c->val[i + 8], + c->val[i + 9], c->val[i + 10], c->val[i + 11]); + lua_pushstring(L,tmp); +} + +#define _extract_property(_key_, _name_) \ + c = X509_find_entity_property((octet*)H, &_key_, ic, &len); \ + if(c) { \ + lua_pushstring(L,_name_); \ + push_entity_property(L,H,c,len); \ + lua_settable(L,-3); } + +static int extract_issuer(lua_State *L) { + BEGIN(); + int c, ic, len; + char *failed_msg = NULL; + const octet *H = o_arg(L, 1); SAFE(H); + ic = X509_find_issuer((octet*)H,&len); + if(!ic) { + failed_msg = "Issuer not found in x509 credential"; + goto end; + } + lua_newtable(L); + _extract_property(X509_CN,"country"); + _extract_property(X509_ON,"org"); + _extract_property(X509_EN,"email"); + _extract_property(X509_LN,"local"); + _extract_property(X509_UN,"unit"); + _extract_property(X509_MN,"name"); + _extract_property(X509_SN,"state"); + _extract_property(X509_AN,"alternate"); + _extract_property(X509_KU,"key"); + _extract_property(X509_BC,"constraints"); +end: + o_free(L,H); + if(failed_msg) { + THROW(failed_msg); + } + END(1); +} + +static int extract_dates(lua_State *L) { + BEGIN(); + int c, ic; + char *failed_msg = NULL; + const octet *H = o_arg(L, 1); SAFE(H); + ic = X509_find_validity((octet*)H); + if(!ic) { + failed_msg = "Validity not found in x509 credential"; + goto end; + } + lua_newtable(L); + c = X509_find_start_date((octet*)H, ic); + if(c) { + lua_pushstring(L,"created"); \ + push_date(L,H,c); + lua_settable(L,-3); + } + c = X509_find_expiry_date((octet*)H, ic); + if(c) { + lua_pushstring(L,"expires"); \ + push_date(L,H,c); + lua_settable(L,-3); + } +end: + o_free(L,H); + if(failed_msg) { + THROW(failed_msg); + } + END(1); +} + int luaopen_x509(lua_State *L) { (void)L; const struct luaL_Reg x509_class[] = { @@ -149,6 +231,8 @@ int luaopen_x509(lua_State *L) { {"extract_cert_sig", extract_cert_sig}, {"extract_pubkey", extract_pubkey}, {"extract_seckey", extract_seckey}, + {"extract_issuer", extract_issuer}, + {"extract_dates", extract_dates}, {NULL,NULL} }; const struct luaL_Reg x509_methods[] = { diff --git a/test/lua/x509.lua b/test/lua/x509.lua index cf0781151..11276701e 100644 --- a/test/lua/x509.lua +++ b/test/lua/x509.lua @@ -32,10 +32,15 @@ sig = x509.extract_cert_sig(pem) pk = x509.extract_pubkey(cert) I.print({cert=cert, sig=sig, pubkey=pk}) +issuer = x509.extract_issuer(cert) +I.print({issuer=issuer}) + +dates = x509.extract_dates(cert) +I.print({dates=dates}) + assert( P256.verify(pk,cert,sig) ) -key = I.spy( x509.extract_seckey( +key = x509.extract_seckey( OCTET.from_base64(x509.pem_to_base64(KEY)) -)) - +) assert( P256.pubgen(key) == pk) From fd703d151a81772a99a9176a4864a43784f01aea Mon Sep 17 00:00:00 2001 From: Jaromil Date: Thu, 23 Jan 2025 19:33:34 +0100 Subject: [PATCH 07/14] fix: additional check upon issuer info extractions --- src/zen_x509.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/zen_x509.c b/src/zen_x509.c index 833863157..961c04687 100644 --- a/src/zen_x509.c +++ b/src/zen_x509.c @@ -158,10 +158,12 @@ static void push_date(lua_State *L, const octet *c, int i) { #define _extract_property(_key_, _name_) \ c = X509_find_entity_property((octet*)H, &_key_, ic, &len); \ - if(c) { \ + if(c!=0) { \ + if(!len)zerror(L,"X509 issuer property %s has zero length",_name_);\ + else { \ lua_pushstring(L,_name_); \ push_entity_property(L,H,c,len); \ - lua_settable(L,-3); } + lua_settable(L,-3); } } static int extract_issuer(lua_State *L) { BEGIN(); From 123e78d6d2862774b182769f6fb9eb0d23d3525e Mon Sep 17 00:00:00 2001 From: Jaromil Date: Fri, 24 Jan 2025 05:28:35 +0100 Subject: [PATCH 08/14] feat: new hexdump debugging function to print hex buffer --- src/zen_error.c | 10 ++++++++++ src/zen_error.h | 1 + 2 files changed, 11 insertions(+) diff --git a/src/zen_error.c b/src/zen_error.c index 97bc5ac16..149402ba9 100644 --- a/src/zen_error.c +++ b/src/zen_error.c @@ -40,6 +40,7 @@ #include #include #include +#include // simple inline duplicate function wrapper also in zen_io.c static inline void _zen_error_write(int fd, const void *buf, size_t count) { @@ -255,6 +256,15 @@ int warning(void *L, const char *format, ...) { return 0; } +int hexdump(void *L, const char *src, size_t len) { + octet *o = o_alloc(L, (len*2)+2); + buf2hex(o->val,src,len); + o->len = strlen(o->val); + zen_log(L, LOG_VERBOSE, o); + o_free((lua_State*)L,o); + return 0; +} + int lua_fatal(lua_State *L) { return lua_error(L); } diff --git a/src/zen_error.h b/src/zen_error.h index 7fc4dc2d6..08bcb62fb 100644 --- a/src/zen_error.h +++ b/src/zen_error.h @@ -81,6 +81,7 @@ HEDLEY_PRINTF_FORMAT(2,3) int act(void *L, const char *format, ...); // DEBUG HEDLEY_PRINTF_FORMAT(2,3) int warning(void *L, const char *format, ...); // WARN +int hexdump(void *L, const char *src, size_t len); // DEBUG hex sequence void json_start(void *L); void json_end(void *L); From 9b36e0213f52d4835cbf2728d1ba81e983457162 Mon Sep 17 00:00:00 2001 From: Jaromil Date: Fri, 24 Jan 2025 05:28:56 +0100 Subject: [PATCH 09/14] fix: correctly parse and print x509 SAN with multiple entries --- src/zen_x509.c | 154 ++++++++++++++++++++++++++++++++++++++++++++-- test/lua/x509.lua | 10 +++ 2 files changed, 158 insertions(+), 6 deletions(-) diff --git a/src/zen_x509.c b/src/zen_x509.c index 961c04687..7b4c45fd7 100644 --- a/src/zen_x509.c +++ b/src/zen_x509.c @@ -140,7 +140,7 @@ static int extract_seckey(lua_State *L) { END(1); } -static void push_entity_property(lua_State *L, const octet *H, int c, int len) { +static void push_entity(lua_State *L, const octet *H, int c, int len) { char tmp[2048]; snprintf(tmp,len,"%s",&H->val[c]); lua_pushstring(L,tmp); @@ -162,7 +162,16 @@ static void push_date(lua_State *L, const octet *c, int i) { if(!len)zerror(L,"X509 issuer property %s has zero length",_name_);\ else { \ lua_pushstring(L,_name_); \ - push_entity_property(L,H,c,len); \ + push_entity(L,H,c,len); \ + lua_settable(L,-3); } } + +#define _extract_extension(_key_, _name_) \ + c = X509_find_extension((octet*)H, &_key_, ic, &len); \ + if(c!=0) { \ + if(!len)zerror(L,"X509 issuer property %s has zero length",_name_);\ + else { \ + lua_pushstring(L,_name_); \ + push_entity(L,H,c,len); \ lua_settable(L,-3); } } static int extract_issuer(lua_State *L) { @@ -176,16 +185,39 @@ static int extract_issuer(lua_State *L) { goto end; } lua_newtable(L); + _extract_property(X509_ON,"owner"); + _extract_property(X509_CN,"country"); + _extract_property(X509_EN,"email"); + _extract_property(X509_LN,"local"); + _extract_property(X509_UN,"unit"); + _extract_property(X509_MN,"name"); + _extract_property(X509_SN,"state"); +end: + o_free(L,H); + if(failed_msg) { + THROW(failed_msg); + } + END(1); +} + +static int extract_subject(lua_State *L) { + BEGIN(); + int c, ic, len; + char *failed_msg = NULL; + const octet *H = o_arg(L, 1); SAFE(H); + ic = X509_find_subject((octet*)H,&len); + if(!ic) { + failed_msg = "Issuer not found in x509 credential"; + goto end; + } + lua_newtable(L); + _extract_property(X509_ON,"owner"); _extract_property(X509_CN,"country"); - _extract_property(X509_ON,"org"); _extract_property(X509_EN,"email"); _extract_property(X509_LN,"local"); _extract_property(X509_UN,"unit"); _extract_property(X509_MN,"name"); _extract_property(X509_SN,"state"); - _extract_property(X509_AN,"alternate"); - _extract_property(X509_KU,"key"); - _extract_property(X509_BC,"constraints"); end: o_free(L,H); if(failed_msg) { @@ -194,6 +226,113 @@ static int extract_issuer(lua_State *L) { END(1); } + +static int extract_extensions(lua_State *L) { + BEGIN(); + int c, ic, len; + char *failed_msg = NULL; + const octet *H = o_arg(L, 1); SAFE(H); + ic = X509_find_extensions((octet*)H); + if(!ic) { + failed_msg = "Issuer not found in x509 credential"; + goto end; + } + lua_newtable(L); + _extract_extension(X509_AN,"SAN"); + _extract_extension(X509_KU,"key"); + _extract_extension(X509_BC,"constraints"); +end: + o_free(L,H); + if(failed_msg) { + THROW(failed_msg); + } + END(1); +} + +// In an X.509 certificate's SAN (Subject Alternative Name) field, the +// GeneralName component can represent various types, each identified +// by unique ASN.1 tags. Apart from URIs, here are other types you may +// encounter, with their corresponding hex tags: +// - Email Address: 81 (IA5String, email) +// - DNS Name: 82 (IA5String, dnsName) +// - X.400 Address: 83 +// - Directory Name: 85 +// - RFC822 Name: A0 (otherName) +// - IP Address: 87 (OCTET STRING, iPAddress) +// - OID (Registered ID): 88 (OBJECT IDENTIFIER, registeredID) +// Each type has its specific encoding. Examples in Hex: +// - Email Address: 81 0c 6578616d706c65406578616d706c652e636f6d +// (IA5String with email example@example.com) +// - DNS Name: 82 0c 6578616d706c652e636f6d +// (IA5String with DNS example.com) +// - IP Address: 87 04 c0a80001 (OCTET STRING with IP 192.168.0.1) +// Within a SAN field, multiple GeneralNames can appear sequenced, +// each prefixed by its identifier hex value, to provide varied +// alternative names. + +// extract subject alternative names +static int extract_san(lua_State *L) { + BEGIN(); + int c, ic, len; + char *failed_msg = NULL; + char *tmp; + const octet *H = o_arg(L, 1); SAFE(H); + ic = X509_find_extensions((octet*)H); + if(!ic) { + failed_msg = "Issuer not found in x509 credential"; + goto end; + } + c = X509_find_extension((octet*)H, &X509_AN, ic, &len); + if(c!=0 && + H->val[c]==0x04 && // ASN.1 octet string + // H->val[ic+1] // octet length is unused + H->val[c+2]==0x30) // ASN.1 sequence + { + int seqlen = H->val[c+3]; + char *p = &H->val[c+4]; + char *end = p + seqlen; + tmp = calloc(seqlen, 1); + lua_newtable(L); + for(int cc=1; p < end; cc++) { + uint8_t type = *p++; + int len = *p++; + lua_pushnumber(L,cc); + lua_newtable(L); + lua_pushstring(L,"data"); + snprintf(tmp,len,"%s",p); + lua_pushstring(L,tmp); + lua_settable(L,-3); + lua_pushstring(L,"type"); + sprintf(tmp,"%s", + type==0x81?"email": + type==0x82?"dns": + type==0x83?"X400": + type==0x85?"dir": + type==0x86?"url": + type==0xA0?"RFC822": + type==0x87?"ip": + type==0x88?"OID": + "unknown"); + lua_pushstring(L,tmp); + lua_settable(L,-3); + // Set the inner table to the outer table + lua_settable(L, -3); + p += len; + } + free(tmp); + } + end: + o_free(L,H); + if(failed_msg) { + THROW(failed_msg); + } + END(1); +} + + // _extract_property(X509_AN,"alternate"); + // _extract_property(X509_KU,"key"); + // _extract_property(X509_BC,"constraints"); + static int extract_dates(lua_State *L) { BEGIN(); int c, ic; @@ -234,6 +373,9 @@ int luaopen_x509(lua_State *L) { {"extract_pubkey", extract_pubkey}, {"extract_seckey", extract_seckey}, {"extract_issuer", extract_issuer}, + {"extract_subject", extract_subject}, + {"extract_extensions", extract_extensions}, + {"extract_san", extract_san}, {"extract_dates", extract_dates}, {NULL,NULL} }; diff --git a/test/lua/x509.lua b/test/lua/x509.lua index 11276701e..6f5eac072 100644 --- a/test/lua/x509.lua +++ b/test/lua/x509.lua @@ -35,6 +35,16 @@ I.print({cert=cert, sig=sig, pubkey=pk}) issuer = x509.extract_issuer(cert) I.print({issuer=issuer}) +subj = x509.extract_subject(cert) +I.print({subject=subj}) + +-- ext = x509.extract_extensions(cert) +-- I.print({extensions=ext, +-- san_hex=OCTET.from_string(ext.SAN):hex()}) + +san = x509.extract_san(cert) +I.print({SAN=san}) + dates = x509.extract_dates(cert) I.print({dates=dates}) From 0cd85f1d732508ddeccf4e121bd3e5ac97b7edf3 Mon Sep 17 00:00:00 2001 From: Jaromil Date: Mon, 27 Jan 2025 10:51:15 +0100 Subject: [PATCH 10/14] feat: new mem find/copy/paste functions for octet bytes this comes handy while working on binary encapsulation formats like x509 so we can find sequences of bytes in an octet, plus copy and paste them. --- src/zen_octet.c | 154 +++++++++++++++++++++++++++++++++++++++ test/lua/memmem.lua | 13 ++++ test/lua/primitives.bats | 1 + 3 files changed, 168 insertions(+) create mode 100644 test/lua/memmem.lua diff --git a/src/zen_octet.c b/src/zen_octet.c index 425e7bfe0..94cc731ff 100644 --- a/src/zen_octet.c +++ b/src/zen_octet.c @@ -1998,6 +1998,152 @@ static int lesser_than(lua_State *L) { END(1); } + +/*** +Finds a needle sequence of bytes in a haystack octet and returns the +position where it has been found (counting from 0) or nil when not +found. + + @function OCTET.find(haystack,needle,pos) + @param haystack the octet in which to find the needle + @param needle the octet needle to search for + @int pos (optional) the positio to start searching in haystack + @return a number indicating the position found in haystack or nil +*/ +static int memfind(lua_State *L) { + BEGIN(); + const octet *haystack = o_arg(L,1); + const octet *needle = o_arg(L,2); + if(needle->len>=haystack->len) { + lua_pushnil(L); + zerror(L,"Octet:substr called on a needle bigger than haystack"); + goto end; + } + const int pos = luaL_optnumber(L, 3, 0); + char *start = haystack->val; + if(pos>0) { + if(pos>=haystack->len) { + lua_pushnil(L); + zerror(L,"Octet:find position (3rd arg) out of haystack"); + goto end; + } + if(haystack->len-poslen) { + lua_pushnil(L); + zerror(L,"Octet:find position (3rd arg) squeezes out needle"); + goto end; + } + start += pos; + } + char *res = (char*) + memmem(start, haystack->len-pos, + needle->val, needle->len); + if(!res) { // not found + lua_pushnil(L); + } else { + lua_pushnumber(L, (uint32_t)(res - haystack->val)); + } + end: + o_free(L,needle); + o_free(L,haystack); + END(1); +} + +/*** + Copies out a needle octet from an haystack octet starting at + position and long as indicated. + + @function OCTET.copy(haystack, start, length) + @param haystack octet from which we copy bytes out into needle + @int start position, begins from 0 + @int length of byte sequence to copy + @return new octet copied out +*/ +static int memcopy(lua_State *L) { + BEGIN(); + char *failed_msg = NULL; + const octet *src = NULL; + octet *dst = NULL; + int start, length; + src = o_arg(L, 1); + if(!src) { + failed_msg = "Could not allocate OCTET"; + goto end; + } + start = luaL_optnumber(L, 2, 0); + if(start < 0 || start > src->len) { + zerror(L, "Octet:copy starting position out of bounds: %i", start); + failed_msg = "Cannot copy octet"; + goto end; + } + length = luaL_optnumber(L, 3, 0); + if(start+length > src->len) { + zerror(L, "invalid octet:copy() length too big: %i", length); + failed_msg = "Cannot copy octet"; + goto end; + } + dst = o_new(L, length+1); + if(!dst) { + failed_msg = "Cannot allocate octet memory"; + goto end; + } + memcpy(dst->val, src->val+start, length); + dst->len = length; +end: + o_free(L, src); + if(failed_msg) { + THROW(failed_msg); + } + END(1); +} + + +/*** + Paste a needle octet into an haystack octet starting at position + and overwriting all its byte values in place. + + @function OCTET.paste(haystack, needle, start) + @param haystack octet destination in which to copy needle + @param needle octet source of needle bytes + @int length of byte sequence to copy from needle + @return bool true on success, false on failure +*/ +static int mempaste(lua_State *L) { + BEGIN(); + char *failed_msg = NULL; + int start; + const octet *hay = o_arg(L, 1); + if(!hay) { + failed_msg = "Cannot allocate octet memory"; + goto end; + } + const octet *src = o_arg(L,2); + if(!src) { + failed_msg = "Cannot allocate octet memory"; + goto end; + } + if(src->len > hay->len) { + zerror(L, "Octet:paste needle size (%i) exceeds haystack (%i)", + src->len, hay->len); + failed_msg = "Cannot paste octet"; + goto end; + } + start = luaL_optnumber(L, 3, 0); + if(start < 1 || start >= hay->len || start+src->len > hay->len) { + zerror(L, "Octet:paste starting position out of bounds: %i", start); + failed_msg = "Cannot paste octet"; + goto end; + } + octet *res = o_dup(L,hay); + memcpy(res->val+start, src->val, src->len); +end: + o_free(L, src); + o_free(L, hay); + if(failed_msg) { + THROW(failed_msg); + } + END(1); +} + int luaopen_octet(lua_State *L) { (void)L; const struct luaL_Reg octet_class[] = { @@ -2056,6 +2202,10 @@ int luaopen_octet(lua_State *L) { {"popcount_hamming", popcount_hamming_distance}, {"to_segwit", to_segwit_address}, {"from_segwit", from_segwit_address}, + {"find", memfind}, + {"copy", memcopy}, + {"paste", mempaste}, + {NULL,NULL} }; const struct luaL_Reg octet_methods[] = { @@ -2092,6 +2242,10 @@ int luaopen_octet(lua_State *L) { {"compact_ascii", compact_ascii}, {"elide_at_start", elide_at_start}, {"fillrepeat", fillrepeat}, + {"find", memfind}, + {"copy", memcopy}, + {"paste", mempaste}, + // {"zcash_topoint", zcash_topoint}, // idiomatic operators {"__len",octet_size}, diff --git a/test/lua/memmem.lua b/test/lua/memmem.lua new file mode 100644 index 000000000..85067c2fb --- /dev/null +++ b/test/lua/memmem.lua @@ -0,0 +1,13 @@ +printerr'TEST memmem operations on octets (substr etc.)' + +haystack = O.from_string'Lorem ipsum dolor amet' -- 22 chars +needle = O.from_string'dolor' +-- I.print({hay_len=#haystack, +-- hay_last=haystack:copy(#haystack-1,1):string()}) +assert(haystack:copy(#haystack-1,1):string()=='t') +assert(haystack:copy(0,1):string()=='L') +-- I.print{haystack=haystack, needle=needle} +pos = haystack:find(needle) +-- I.print({pos=pos,needle_len=#needle}) +assert(haystack:copy(pos,#needle):string()=='dolor') +assert(not haystack:find(needle,16)) diff --git a/test/lua/primitives.bats b/test/lua/primitives.bats index eec9ae368..a992122dd 100644 --- a/test/lua/primitives.bats +++ b/test/lua/primitives.bats @@ -13,4 +13,5 @@ load ../bats_setup Z zenroom_strings.lua Z xor.lua Z trim.lua + Z memmem.lua } From a69fe77aac1ef0f60770658140a014cee5ee9b1b Mon Sep 17 00:00:00 2001 From: Jaromil Date: Mon, 27 Jan 2025 10:52:24 +0100 Subject: [PATCH 11/14] fix: small bug in native octet code error logging --- src/zen_octet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zen_octet.c b/src/zen_octet.c index 94cc731ff..cc3a84d00 100644 --- a/src/zen_octet.c +++ b/src/zen_octet.c @@ -222,7 +222,7 @@ octet* o_new(lua_State *L, const int size) { o->val = malloc(size +0x0f); if(HEDLEY_UNLIKELY(o->val==NULL)) { zerror(L, "Cannot create octet, malloc failure"); - zerror("%s: %s",__func__,strerror(errno)); + zerror(L, "%s: %s",__func__,strerror(errno)); return NULL; } o->len = 0; o->max = size; From 54b5c41905515e99d524d5b592552328dbde97f7 Mon Sep 17 00:00:00 2001 From: Jaromil Date: Mon, 27 Jan 2025 10:52:53 +0100 Subject: [PATCH 12/14] build: new quick-asan target to rebuild C without rebuiling lua this is not even appearing in the list of make targets but is very useful when working on C code since it saves the time it takes to run embed-lua every time in case no change was applied to lua libs --- Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Makefile b/Makefile index 8720bed9d..e86c98790 100644 --- a/Makefile +++ b/Makefile @@ -35,6 +35,10 @@ debug-asan: ## Address sanitizer debug build $(MAKE) -f build/posix.mk ASAN=1 $(MAKE) -f build/posix.mk libzenroom.so ASAN=1 +quick-asan: # quick debug rebuild skipping deps and embed-lua + $(MAKE) -f build/posix.mk ASAN=1 BUILD_DEPS="" + $(MAKE) -f build/posix.mk libzenroom.so ASAN=1 BUILD_DEPS="" + musl: ## Static executable for Musl $(MAKE) -f build/musl.mk From 3bd9686e1322b6b51946f8b4fd5521315454aaf3 Mon Sep 17 00:00:00 2001 From: Jaromil Date: Mon, 27 Jan 2025 11:00:57 +0100 Subject: [PATCH 13/14] fix: provide memmem for windows builds --- src/zen_octet.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/zen_octet.c b/src/zen_octet.c index cc3a84d00..345ee6689 100644 --- a/src/zen_octet.c +++ b/src/zen_octet.c @@ -1999,6 +1999,32 @@ static int lesser_than(lua_State *L) { } +// windows has no memmem, we provide our own +#if defined(_WIN32) +HEDLEY_NON_NULL(1,3) +static void *memmem(const void *src,int srclen,const void *dst,int dstlen) { + unsigned char *csrc = (unsigned char *)src; + unsigned char *cdst = (unsigned char *)dst; + unsigned char *tptr,*cptr; + int searchlen; + int ndx = 0; + while (ndx<=srclen) { + cptr = &csrc[ndx]; + if ((searchlen = srclen-ndx-dstlen+1) <= 0) { + return NULL; + } + if ((tptr = memchr(cptr,*cdst,searchlen)) == NULL) { + return NULL; + } + if (memcmp(tptr,cdst,dstlen) == 0) { + return tptr; + } + ndx += tptr-cptr+1; + } + return NULL; +} +#endif + /*** Finds a needle sequence of bytes in a haystack octet and returns the position where it has been found (counting from 0) or nil when not From 04c6f83422c0737e60ce38bb9136b5d500dafdbe Mon Sep 17 00:00:00 2001 From: Jaromil Date: Mon, 27 Jan 2025 12:42:36 +0100 Subject: [PATCH 14/14] note on post-quantum x509 incomplete test --- test/api/x509_postquantum.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/api/x509_postquantum.c b/test/api/x509_postquantum.c index 0b67dac97..fde4b759f 100644 --- a/test/api/x509_postquantum.c +++ b/test/api/x509_postquantum.c @@ -1,4 +1,6 @@ // test x509 for post-quantum safe zenroom +// incomplete. for the generation of the certificate see: +// https://gist.github.com/jaromil/5cdd0580c643d040d8cad0c026a98931 #include #include // for octet support only