Separate the SCT List parser from the SCT List viewer
authorRob Stradling <rob@comodo.com>
Mon, 12 May 2014 13:40:19 +0000 (14:40 +0100)
committerDr. Stephen Henson <steve@openssl.org>
Tue, 10 Jun 2014 23:10:45 +0000 (00:10 +0100)
(cherry picked from commit fd2309aa29e3ea00e445f03407820398962c0b94)

crypto/stack/safestack.h
crypto/x509v3/v3_scts.c

index 076d001d8003fc2c57f6168481f3bec882280d5c..e7e2746c31ca8e82595c6e55a379aac6b182a538 100644 (file)
@@ -1481,6 +1481,28 @@ DECLARE_SPECIAL_STACK_OF(OPENSSL_BLOCK, void)
 #define sk_POLICY_MAPPING_sort(st) SKM_sk_sort(POLICY_MAPPING, (st))
 #define sk_POLICY_MAPPING_is_sorted(st) SKM_sk_is_sorted(POLICY_MAPPING, (st))
 
+#define sk_SCT_new(cmp) SKM_sk_new(SCT, (cmp))
+#define sk_SCT_new_null() SKM_sk_new_null(SCT)
+#define sk_SCT_free(st) SKM_sk_free(SCT, (st))
+#define sk_SCT_num(st) SKM_sk_num(SCT, (st))
+#define sk_SCT_value(st, i) SKM_sk_value(SCT, (st), (i))
+#define sk_SCT_set(st, i, val) SKM_sk_set(SCT, (st), (i), (val))
+#define sk_SCT_zero(st) SKM_sk_zero(SCT, (st))
+#define sk_SCT_push(st, val) SKM_sk_push(SCT, (st), (val))
+#define sk_SCT_unshift(st, val) SKM_sk_unshift(SCT, (st), (val))
+#define sk_SCT_find(st, val) SKM_sk_find(SCT, (st), (val))
+#define sk_SCT_find_ex(st, val) SKM_sk_find_ex(SCT, (st), (val))
+#define sk_SCT_delete(st, i) SKM_sk_delete(SCT, (st), (i))
+#define sk_SCT_delete_ptr(st, ptr) SKM_sk_delete_ptr(SCT, (st), (ptr))
+#define sk_SCT_insert(st, val, i) SKM_sk_insert(SCT, (st), (val), (i))
+#define sk_SCT_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(SCT, (st), (cmp))
+#define sk_SCT_dup(st) SKM_sk_dup(SCT, st)
+#define sk_SCT_pop_free(st, free_func) SKM_sk_pop_free(SCT, (st), (free_func))
+#define sk_SCT_shift(st) SKM_sk_shift(SCT, (st))
+#define sk_SCT_pop(st) SKM_sk_pop(SCT, (st))
+#define sk_SCT_sort(st) SKM_sk_sort(SCT, (st))
+#define sk_SCT_is_sorted(st) SKM_sk_is_sorted(SCT, (st))
+
 #define sk_SRP_gN_new(cmp) SKM_sk_new(SRP_gN, (cmp))
 #define sk_SRP_gN_new_null() SKM_sk_new_null(SRP_gN)
 #define sk_SRP_gN_free(st) SKM_sk_free(SRP_gN, (st))
index 457d5acaaaa4b85c0ed960fddf31d54db2a296e2..3bf1579310df1703e821e543b94ffd966cf82af7 100644 (file)
 #include "cryptlib.h"
 #include <openssl/asn1.h>
 #include <openssl/x509v3.h>
-#include <openssl/bn.h>
 #include "../ssl/ssl_locl.h"
 
 #if (defined(_WIN32) || defined(_WIN64)) && !defined(__MINGW32__)
-#define SCTS_TIMESTAMP unsigned __int64
+#define SCT_TIMESTAMP unsigned __int64
 #elif defined(__arch64__)
-#define SCTS_TIMESTAMP unsigned long
+#define SCT_TIMESTAMP unsigned long
 #else
-#define SCTS_TIMESTAMP unsigned long long
+#define SCT_TIMESTAMP unsigned long long
 #endif
 
-#define n2l8(c,l)      (l =((SCTS_TIMESTAMP)(*((c)++)))<<56, \
-                        l|=((SCTS_TIMESTAMP)(*((c)++)))<<48, \
-                        l|=((SCTS_TIMESTAMP)(*((c)++)))<<40, \
-                        l|=((SCTS_TIMESTAMP)(*((c)++)))<<32, \
-                        l|=((SCTS_TIMESTAMP)(*((c)++)))<<24, \
-                        l|=((SCTS_TIMESTAMP)(*((c)++)))<<16, \
-                        l|=((SCTS_TIMESTAMP)(*((c)++)))<< 8, \
-                        l|=((SCTS_TIMESTAMP)(*((c)++))))
+#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)++))))
 
+typedef struct SCT_st {
+       /* The encoded SCT */
+       unsigned char *sct;
+       unsigned short sctlen;
 
-static int i2r_scts(X509V3_EXT_METHOD *method, ASN1_OCTET_STRING *oct, BIO *out, int indent);
+       /* 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,
+{ 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_scts, NULL,
+(X509V3_EXT_I2R)i2r_SCT_LIST, 0,
 NULL},
 
-{ NID_ct_cert_scts, 0, ASN1_ITEM_ref(ASN1_OCTET_STRING),
+{ NID_ct_cert_scts, 0, NULL,
+0,(X509V3_EXT_FREE)SCT_LIST_free,
+(X509V3_EXT_D2I)d2i_SCT_LIST, 0,
 0,0,0,0,
-0,0,0,0,
-(X509V3_EXT_I2R)i2r_scts, NULL,
+(X509V3_EXT_I2R)i2r_SCT_LIST, 0,
 NULL},
 };
 
-static void tls12_signature_print(BIO *out, const unsigned char *data)
+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 (data[0] == TLSEXT_hash_sha256)
+       if (hash_alg == TLSEXT_hash_sha256)
                {
-               if (data[1] == TLSEXT_signature_rsa)
+               if (sig_alg == TLSEXT_signature_rsa)
                        nid = NID_sha256WithRSAEncryption;
-               else if (data[1] == TLSEXT_signature_ecdsa)
+               else if (sig_alg == TLSEXT_signature_ecdsa)
                        nid = NID_ecdsa_with_SHA256;
                }
        if (nid == NID_undef)
-               BIO_printf(out, "%02X%02X", data[0], data[1]);
+               BIO_printf(out, "%02X%02X", hash_alg, sig_alg);
        else
                BIO_printf(out, "%s", OBJ_nid2ln(nid));
        }
 
-static void timestamp_print(BIO *out, SCTS_TIMESTAMP timestamp)
+static void timestamp_print(BIO *out, SCT_TIMESTAMP timestamp)
        {
        ASN1_GENERALIZEDTIME *gen;
        char genstr[20];
@@ -133,38 +160,72 @@ static void timestamp_print(BIO *out, SCTS_TIMESTAMP timestamp)
        ASN1_GENERALIZEDTIME_free(gen);
        }
 
-static int i2r_scts(X509V3_EXT_METHOD *method, ASN1_OCTET_STRING *oct,
-                      BIO *out, int indent)
+static void SCT_free(SCT *sct)
+       {
+       if (sct)
+               {
+               if (sct->sct) OPENSSL_free(sct->sct);
+               OPENSSL_free(sct);
+               }
+       }
+
+static void SCT_LIST_free(STACK_OF(SCT) *a)
+       {
+       sk_SCT_pop_free(a, SCT_free);
+       }
+
+static STACK_OF(SCT) *d2i_SCT_LIST(STACK_OF(SCT) **a, const unsigned char **pp,
+                                  long length)
        {
-       SCTS_TIMESTAMP timestamp;
-       unsigned char* data = oct->data;
+       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)
-               return 0;
-       n2s(data, listlen);
+               goto done;
+       p = oct->data;
+       n2s(p, listlen);
        if (listlen != oct->length - 2)
-               return 0;
+               goto done;
+
+       if ((sk=sk_SCT_new_null()) == NULL)
+               goto done;
 
        while (listlen > 0)
                {
                if (listlen < 2)
-                       return 0;
-               n2s(data, sctlen);
+                       goto err;
+               n2s(p, sctlen);
                listlen -= 2;
 
                if ((sctlen < 1) || (sctlen > listlen))
-                       return 0;
+                       goto err;
                listlen -= sctlen;
 
-               BIO_printf(out, "%*sSigned Certificate Timestamp:", indent,
-                          "");
-               BIO_printf(out, "\n%*sVersion   : ", indent + 4, "");
-
-               if (*data == 0)         /* SCT v1 */
+               sct = OPENSSL_malloc(sizeof(SCT));
+               if (!sct)
+                       goto err;
+               if (!sk_SCT_push(sk, sct))
                        {
-                       BIO_printf(out, "v1(0)");
+                       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;
@@ -173,56 +234,96 @@ static int i2r_scts(X509V3_EXT_METHOD *method, ASN1_OCTET_STRING *oct,
                         * (2 bytes + ?)  CtExtensions extensions;
                         */
                        if (sctlen < 43)
-                               return 0;
+                               goto err;
                        sctlen -= 43;
 
-                       BIO_printf(out, "\n%*sLog ID    : ", indent + 4, "");
-                       BIO_hex_string(out, indent + 16, 16, data + 1, 32);
+                       sct->logid = p2;
+                       sct->logidlen = 32;
+                       p2 += 32;
 
-                       data += 33;
-                       n2l8(data, timestamp);
-                       BIO_printf(out, "\n%*sTimestamp : ", indent + 4, "");
-                       timestamp_print(out, timestamp);
+                       n2l8(p2, sct->timestamp);
 
-                       n2s(data, fieldlen);
+                       n2s(p2, fieldlen);
                        if (sctlen < fieldlen)
-                               return 0;
+                               goto err;
+                       sct->ext = p2;
+                       sct->extlen = fieldlen;
+                       p2 += fieldlen;
                        sctlen -= fieldlen;
-                       BIO_printf(out, "\n%*sExtensions: ", indent + 4, "");
-                       if (fieldlen == 0)
-                               BIO_printf(out, "none");
-                       else
-                               BIO_hex_string(out, indent + 16, 16, data,
-                                              fieldlen);
-                       data += fieldlen;
 
                        /* digitally-signed struct header:
-                        * (1 byte) Hash algorithm
-                        * (1 byte) Signature algorithm
-                        * (2 bytes + ?) Signature
+                        * (1 byte)       Hash algorithm
+                        * (1 byte)       Signature algorithm
+                        * (2 bytes + ?)  Signature
                         */
                        if (sctlen < 4)
-                               return 0;
+                               goto err;
                        sctlen -= 4;
 
-                       BIO_printf(out, "\n%*sSignature : ", indent + 4, "");
-                       tls12_signature_print(out, data);
-                       data += 2;
-                       n2s(data, fieldlen);
+                       sct->hash_alg = *p2++;
+                       sct->sig_alg = *p2++;
+                       n2s(p2, fieldlen);
                        if (sctlen != fieldlen)
-                               return 0;
+                               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)
+       {
+       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, data, fieldlen);
-                       data += fieldlen;
+                       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, data, sctlen);
-                       data += sctlen;
+                       BIO_hex_string(out, indent + 16, 16, sct->sct,
+                                      sct->sctlen);
                        }
 
-               if (listlen > 0) BIO_printf(out, "\n");
+               if (++i < sk_SCT_num(sct_list)) BIO_printf(out, "\n");
                }
 
        return 1;