X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=crypto%2Fx509v3%2Fv3_scts.c;h=e70d5e927f362eeb0a88dd17491969fb9f58e882;hp=0868a7bb9220014b14a9601872c6c435f52a5b74;hb=2743e38c2f4bcb00142d8c65e48a66f547033a64;hpb=dcfe8df148d225aa15fdd0eba486a028ad4b06dc diff --git a/crypto/x509v3/v3_scts.c b/crypto/x509v3/v3_scts.c index 0868a7bb92..e70d5e927f 100644 --- a/crypto/x509v3/v3_scts.c +++ b/crypto/x509v3/v3_scts.c @@ -1,5 +1,6 @@ /* v3_scts.c */ -/* Written by Rob Stradling (rob@comodo.com) for the OpenSSL project 2014. +/* + * Written by Rob Stradling (rob@comodo.com) for the OpenSSL project 2014. */ /* ==================================================================== * Copyright (c) 2014 The OpenSSL Project. All rights reserved. @@ -9,7 +10,7 @@ * are met: * * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. + * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in @@ -55,218 +56,268 @@ * */ - #include #include "cryptlib.h" #include -#include "o_time.h" #include -#include "../ssl/ssl_locl.h" +#include "../../ssl/ssl_locl.h" + +#if (defined(_WIN32) || defined(_WIN64)) && !defined(__MINGW32__) +# define SCT_TIMESTAMP unsigned __int64 +#elif defined(__arch64__) +# define SCT_TIMESTAMP unsigned long +#else +# define SCT_TIMESTAMP unsigned long long +#endif + +#define n2l8(c,l) (l =((SCT_TIMESTAMP)(*((c)++)))<<56, \ + l|=((SCT_TIMESTAMP)(*((c)++)))<<48, \ + l|=((SCT_TIMESTAMP)(*((c)++)))<<40, \ + l|=((SCT_TIMESTAMP)(*((c)++)))<<32, \ + l|=((SCT_TIMESTAMP)(*((c)++)))<<24, \ + l|=((SCT_TIMESTAMP)(*((c)++)))<<16, \ + l|=((SCT_TIMESTAMP)(*((c)++)))<< 8, \ + l|=((SCT_TIMESTAMP)(*((c)++)))) -static int i2r_scts(X509V3_EXT_METHOD *method, ASN1_OCTET_STRING *oct, BIO *out, int indent); +typedef struct SCT_st { + /* The encoded SCT */ + unsigned char *sct; + unsigned short sctlen; + /* + * Components of the SCT. "logid", "ext" and "sig" point to addresses + * inside "sct". + */ + unsigned char version; + unsigned char *logid; + unsigned short logidlen; + SCT_TIMESTAMP timestamp; + unsigned char *ext; + unsigned short extlen; + unsigned char hash_alg; + unsigned char sig_alg; + unsigned char *sig; + unsigned short siglen; +} SCT; + +DECLARE_STACK_OF(SCT) + +static void SCT_LIST_free(STACK_OF(SCT) *a); +static STACK_OF(SCT) *d2i_SCT_LIST(STACK_OF(SCT) **a, + const unsigned char **pp, long length); +static int i2r_SCT_LIST(X509V3_EXT_METHOD *method, STACK_OF(SCT) *sct_list, + BIO *out, int indent); const X509V3_EXT_METHOD v3_ct_scts[] = { -{ NID_ct_precert_scts, 0, ASN1_ITEM_ref(ASN1_OCTET_STRING), -0,0,0,0, -0,0,0,0, -(X509V3_EXT_I2R)i2r_scts, NULL, -NULL}, - -{ NID_ct_cert_scts, 0, ASN1_ITEM_ref(ASN1_OCTET_STRING), -0,0,0,0, -0,0,0,0, -(X509V3_EXT_I2R)i2r_scts, NULL, -NULL}, + {NID_ct_precert_scts, 0, NULL, + 0, (X509V3_EXT_FREE)SCT_LIST_free, + (X509V3_EXT_D2I)d2i_SCT_LIST, 0, + 0, 0, 0, 0, + (X509V3_EXT_I2R)i2r_SCT_LIST, 0, + NULL}, + + {NID_ct_cert_scts, 0, NULL, + 0, (X509V3_EXT_FREE)SCT_LIST_free, + (X509V3_EXT_D2I)d2i_SCT_LIST, 0, + 0, 0, 0, 0, + (X509V3_EXT_I2R)i2r_SCT_LIST, 0, + NULL}, }; +static void tls12_signature_print(BIO *out, const unsigned char hash_alg, + const unsigned char sig_alg) +{ + int nid = NID_undef; + /* RFC6962 only permits two signature algorithms */ + if (hash_alg == TLSEXT_hash_sha256) { + if (sig_alg == TLSEXT_signature_rsa) + nid = NID_sha256WithRSAEncryption; + else if (sig_alg == TLSEXT_signature_ecdsa) + nid = NID_ecdsa_with_SHA256; + } + if (nid == NID_undef) + BIO_printf(out, "%02X%02X", hash_alg, sig_alg); + else + BIO_printf(out, "%s", OBJ_nid2ln(nid)); +} -/* - * from crypto/asn1/t_x509.c - */ -static const char *mon[12]= - { - "Jan","Feb","Mar","Apr","May","Jun", - "Jul","Aug","Sep","Oct","Nov","Dec" - }; -/* */ +static void timestamp_print(BIO *out, SCT_TIMESTAMP timestamp) +{ + ASN1_GENERALIZEDTIME *gen; + char genstr[20]; + gen = ASN1_GENERALIZEDTIME_new(); + ASN1_GENERALIZEDTIME_adj(gen, (time_t)0, + (int)(timestamp / 86400000), + (timestamp % 86400000) / 1000); + /* + * Note GeneralizedTime from ASN1_GENERALIZETIME_adj is always 15 + * characters long with a final Z. Update it with fractional seconds. + */ + BIO_snprintf(genstr, sizeof(genstr), "%.14s.%03dZ", + ASN1_STRING_data(gen), (unsigned int)(timestamp % 1000)); + ASN1_GENERALIZEDTIME_set_string(gen, genstr); + ASN1_GENERALIZEDTIME_print(out, gen); + ASN1_GENERALIZEDTIME_free(gen); +} +static void SCT_free(SCT *sct) +{ + if (sct) { + if (sct->sct) + OPENSSL_free(sct->sct); + OPENSSL_free(sct); + } +} -/* - * from ssl/t1_lib.c - */ -typedef struct - { - int nid; - int id; - } tls12_lookup; - -static tls12_lookup tls12_md[] = { - {NID_md5, TLSEXT_hash_md5}, - {NID_sha1, TLSEXT_hash_sha1}, - {NID_sha224, TLSEXT_hash_sha224}, - {NID_sha256, TLSEXT_hash_sha256}, - {NID_sha384, TLSEXT_hash_sha384}, - {NID_sha512, TLSEXT_hash_sha512} -}; +static void SCT_LIST_free(STACK_OF(SCT) *a) +{ + sk_SCT_pop_free(a, SCT_free); +} -static tls12_lookup tls12_sig[] = { - {EVP_PKEY_RSA, TLSEXT_signature_rsa}, - {EVP_PKEY_DSA, TLSEXT_signature_dsa}, - {EVP_PKEY_EC, TLSEXT_signature_ecdsa} -}; +static STACK_OF(SCT) *d2i_SCT_LIST(STACK_OF(SCT) **a, + const unsigned char **pp, long length) +{ + ASN1_OCTET_STRING *oct = NULL; + STACK_OF(SCT) *sk = NULL; + SCT *sct; + unsigned char *p, *p2; + unsigned short listlen, sctlen = 0, fieldlen; + + if (d2i_ASN1_OCTET_STRING(&oct, pp, length) == NULL) + return NULL; + if (oct->length < 2) + goto done; + p = oct->data; + n2s(p, listlen); + if (listlen != oct->length - 2) + goto done; + + if ((sk = sk_SCT_new_null()) == NULL) + goto done; + + while (listlen > 0) { + if (listlen < 2) + goto err; + n2s(p, sctlen); + listlen -= 2; -static int tls12_find_nid(int id, tls12_lookup *table, size_t tlen) - { - size_t i; - for (i = 0; i < tlen; i++) - { - if ((table[i].id) == id) - return table[i].nid; - } - return NID_undef; - } - -/* Convert TLS 1.2 signature algorithm extension values into NIDs */ -static void tls1_lookup_sigalg(int *phash_nid, int *psign_nid, - int *psignhash_nid, const unsigned char *data) - { - int sign_nid = 0, hash_nid = 0; - if (!phash_nid && !psign_nid && !psignhash_nid) - return; - if (phash_nid || psignhash_nid) - { - hash_nid = tls12_find_nid(data[0], tls12_md, - sizeof(tls12_md)/sizeof(tls12_lookup)); - if (phash_nid) - *phash_nid = hash_nid; - } - if (psign_nid || psignhash_nid) - { - sign_nid = tls12_find_nid(data[1], tls12_sig, - sizeof(tls12_sig)/sizeof(tls12_lookup)); - if (psign_nid) - *psign_nid = sign_nid; - } - if (psignhash_nid) - { - if (sign_nid && hash_nid) - OBJ_find_sigid_by_algs(psignhash_nid, - hash_nid, sign_nid); - else - *psignhash_nid = NID_undef; - } - } -/* */ - - -static int i2r_scts(X509V3_EXT_METHOD *method, ASN1_OCTET_STRING *oct, - BIO *out, int indent) + if ((sctlen < 1) || (sctlen > listlen)) + goto err; + listlen -= sctlen; + + sct = OPENSSL_malloc(sizeof(SCT)); + if (!sct) + goto err; + if (!sk_SCT_push(sk, sct)) { + OPENSSL_free(sct); + goto err; + } + + sct->sct = OPENSSL_malloc(sctlen); + if (!sct->sct) + goto err; + memcpy(sct->sct, p, sctlen); + sct->sctlen = sctlen; + p += sctlen; + p2 = sct->sct; + + sct->version = *p2++; + if (sct->version == 0) { /* SCT v1 */ + /*- + * Fixed-length header: + * struct { + * (1 byte) Version sct_version; + * (32 bytes) LogID id; + * (8 bytes) uint64 timestamp; + * (2 bytes + ?) CtExtensions extensions; + */ + if (sctlen < 43) + goto err; + sctlen -= 43; + + sct->logid = p2; + sct->logidlen = 32; + p2 += 32; + + n2l8(p2, sct->timestamp); + + n2s(p2, fieldlen); + if (sctlen < fieldlen) + goto err; + sct->ext = p2; + sct->extlen = fieldlen; + p2 += fieldlen; + sctlen -= fieldlen; + + /*- + * digitally-signed struct header: + * (1 byte) Hash algorithm + * (1 byte) Signature algorithm + * (2 bytes + ?) Signature + */ + if (sctlen < 4) + goto err; + sctlen -= 4; + + sct->hash_alg = *p2++; + sct->sig_alg = *p2++; + n2s(p2, fieldlen); + if (sctlen != fieldlen) + goto err; + sct->sig = p2; + sct->siglen = fieldlen; + } + } + + done: + ASN1_OCTET_STRING_free(oct); + return sk; + + err: + SCT_LIST_free(sk); + sk = NULL; + goto done; +} + +static int i2r_SCT_LIST(X509V3_EXT_METHOD *method, STACK_OF(SCT) *sct_list, + BIO *out, int indent) { - BN_ULLONG timestamp; - unsigned char* data = oct->data; - unsigned short listlen, sctlen, fieldlen, linelen; - int signhash_nid; - time_t unix_epoch = 0; - struct tm tm1; - - if (oct->length < 2) - return 0; - n2s(data, listlen); - if (listlen != oct->length - 2) - return 0; - - while (listlen > 0) { - if (listlen < 2) - return 0; - n2s(data, sctlen); - listlen -= 2; - - if ((sctlen < 1) || (sctlen > listlen)) - return 0; - listlen -= sctlen; - - if (*data == 0) { /* v1 SCT */ - /* Fixed-length header: - * struct { - * (1 byte) Version sct_version; - * (32 bytes) LogID id; - * (8 bytes) uint64 timestamp; - * (2 bytes + ?) CtExtensions extensions; - */ - if (sctlen < 43) - return 0; - sctlen -= 43; - - BIO_printf(out, "\n%*sVersion : v1(0)", indent, ""); - - BIO_printf(out, "\n%*sLog ID : ", indent, ""); - BIO_printf(out, "%s:", hex_to_string(data + 1, 16)); - BIO_printf(out, "\n%*s ", indent, ""); - BIO_printf(out, "%s", hex_to_string(data + 17, 16)); - - data += 33; - n2l8(data, timestamp); - OPENSSL_gmtime(&unix_epoch, &tm1); - OPENSSL_gmtime_adj(&tm1, timestamp / 86400000, - (timestamp % 86400000) / 1000); - BIO_printf(out, "\n%*sTimestamp : ", indent, ""); - BIO_printf(out, "%s %2d %02d:%02d:%02d.%03u %d UTC", - mon[tm1.tm_mon], tm1.tm_mday, tm1.tm_hour, - tm1.tm_min, tm1.tm_sec, - (unsigned int)(timestamp % 1000), - tm1.tm_year + 1900); - - n2s(data, fieldlen); - if (sctlen < fieldlen) - return 0; - sctlen -= fieldlen; - BIO_printf(out, "\n%*sExtensions:", indent, ""); - if (fieldlen == 0) - BIO_printf(out, " none"); - for (linelen = 16; fieldlen > 0; ) { - if (linelen > fieldlen) - linelen = fieldlen; - BIO_printf(out, "\n%*s ", indent, ""); - BIO_printf(out, "%s", - hex_to_string(data, linelen)); - if (fieldlen > 16) - BIO_printf(out, ":"); - data += linelen; - fieldlen -= linelen; - } - - /* digitally-signed struct header: - * (1 byte) Hash algorithm - * (1 byte) Signature algorithm - * (2 bytes + ?) Signature - */ - if (sctlen < 4) - return 0; - sctlen -= 4; - - tls1_lookup_sigalg(NULL, NULL, &signhash_nid, data); - data += 2; - n2s(data, fieldlen); - if (sctlen != fieldlen) - return 0; - BIO_printf(out, "\n%*sSignature : ", indent, ""); - BIO_printf(out, "%s", OBJ_nid2ln(signhash_nid)); - for (linelen = 16; fieldlen > 0; ) { - if (linelen > fieldlen) - linelen = fieldlen; - BIO_printf(out, "\n%*s ", indent, - ""); - BIO_printf(out, "%s", - hex_to_string(data, linelen)); - if (fieldlen > 16) - BIO_printf(out, ":"); - data += linelen; - fieldlen -= linelen; - } - - BIO_printf(out, "\n"); - } - } - - return 1; + SCT *sct; + int i; + + for (i = 0; i < sk_SCT_num(sct_list);) { + sct = sk_SCT_value(sct_list, i); + + BIO_printf(out, "%*sSigned Certificate Timestamp:", indent, ""); + BIO_printf(out, "\n%*sVersion : ", indent + 4, ""); + + if (sct->version == 0) { /* SCT v1 */ + BIO_printf(out, "v1(0)"); + + BIO_printf(out, "\n%*sLog ID : ", indent + 4, ""); + BIO_hex_string(out, indent + 16, 16, sct->logid, sct->logidlen); + + BIO_printf(out, "\n%*sTimestamp : ", indent + 4, ""); + timestamp_print(out, sct->timestamp); + + BIO_printf(out, "\n%*sExtensions: ", indent + 4, ""); + if (sct->extlen == 0) + BIO_printf(out, "none"); + else + BIO_hex_string(out, indent + 16, 16, sct->ext, sct->extlen); + + BIO_printf(out, "\n%*sSignature : ", indent + 4, ""); + tls12_signature_print(out, sct->hash_alg, sct->sig_alg); + BIO_printf(out, "\n%*s ", indent + 4, ""); + BIO_hex_string(out, indent + 16, 16, sct->sig, sct->siglen); + } else { /* Unknown version */ + + BIO_printf(out, "unknown\n%*s", indent + 16, ""); + BIO_hex_string(out, indent + 16, 16, sct->sct, sct->sctlen); + } + + if (++i < sk_SCT_num(sct_list)) + BIO_printf(out, "\n"); + } + + return 1; }