mark all block comments that need format preserving so that
[openssl.git] / crypto / x509v3 / v3_scts.c
index 9c560ad483f7ebfbde5cfb59bbda95f34bed9acf..5367271d37f785807fe03ce9392db2838ce32376 100644 (file)
 #include "cryptlib.h"
 #include <openssl/asn1.h>
 #include <openssl/x509v3.h>
-#include <openssl/bn.h>
 #include "../ssl/ssl_locl.h"
 
-static int i2r_scts(X509V3_EXT_METHOD *method, ASN1_OCTET_STRING *oct, BIO *out, int indent);
+#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)++))))
+
+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,
+{ 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, BN_ULLONG timestamp)
+static void timestamp_print(BIO *out, SCT_TIMESTAMP timestamp)
        {
        ASN1_GENERALIZEDTIME *gen;
        char genstr[20];
@@ -115,39 +160,74 @@ static void timestamp_print(BIO *out, BN_ULLONG 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)
        {
-       BN_ULLONG timestamp;
-       unsigned char* data = oct->data;
+       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)
+       {
+       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;
+                       }
 
-                       /* Fixed-length header:
+               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;
@@ -155,56 +235,97 @@ 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
+
+                       /*-
+                        * digitally-signed struct header:
+                        * (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;