make X509_NAME opaque
[openssl.git] / crypto / x509v3 / v3_scts.c
index c6ef0dc901ad948d78fda0c349e325a0398d2cc4..e70d5e927f362eeb0a88dd17491969fb9f58e882 100644 (file)
@@ -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
  *
  */
 
-
 #include <stdio.h>
 #include "cryptlib.h"
 #include <openssl/asn1.h>
 #include <openssl/x509v3.h>
-#include <openssl/bn.h>
-#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)++))))
+
+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 int i2r_scts(X509V3_EXT_METHOD *method, ASN1_OCTET_STRING *oct, BIO *out, int indent);
+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 *data)
-       {
-       int nid = NID_undef;
-       /* RFC6962 only permits two signature algorithms */
-       if (data[0] == TLSEXT_hash_sha256)
-               {
-               if (data[1] == TLSEXT_signature_rsa)
-                       nid = NID_sha256WithRSAEncryption;
-               else if (data[1] == TLSEXT_signature_ecdsa)
-                       nid = NID_ecdsa_with_SHA256;
-               }
-       if (nid == NID_undef)
-               BIO_printf(out, "%02X%02X", data[0], data[1]);
-       else
-               BIO_printf(out, "%s", OBJ_nid2ln(nid));
-       }
-
-static void timestamp_print(BIO *out, BN_ULLONG timestamp)
-       {
-       ASN1_GENERALIZEDTIME *gen;
-       char genstr[20];
-       gen = ASN1_GENERALIZEDTIME_new();
-       ASN1_GENERALIZEDTIME_adj(gen, (time_t)0,
-                                       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 int i2r_scts(X509V3_EXT_METHOD *method, ASN1_OCTET_STRING *oct,
-                      BIO *out, int indent)
-       {
-       BN_ULLONG timestamp;
-       unsigned char* data = oct->data;
-       unsigned short listlen, sctlen = 0, fieldlen;
-
-       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;
-
-               BIO_printf(out, "%*sSigned Certificate Timestamp:", indent,
-                          "");
-
-               if (*data == 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)
-                               return 0;
-                       sctlen -= 43;
-
-                       BIO_printf(out, "\n%*sVersion   : v1(0)", indent + 4,
-                                  "");
-
-                       BIO_printf(out, "\n%*sLog ID    : ", indent + 4, "");
-                       BIO_hex_string(out, indent + 16, 16, data + 1, 32);
-
-                       data += 33;
-                       n2l8(data, timestamp);
-                       BIO_printf(out, "\n%*sTimestamp : ", indent + 4, "");
-                       timestamp_print(out, timestamp);
-
-                       n2s(data, fieldlen);
-                       if (sctlen < fieldlen)
-                               return 0;
-                       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
-                        */
-                       if (sctlen < 4)
-                               return 0;
-                       sctlen -= 4;
-
-                       BIO_printf(out, "\n%*sSignature : ", indent + 4, "");
-                       tls12_signature_print(out, data);
-                       data += 2;
-                       n2s(data, fieldlen);
-                       if (sctlen != fieldlen)
-                               return 0;
-                       BIO_printf(out, "\n%*s            ", indent + 4, "");
-                       BIO_hex_string(out, indent + 16, 16, data, fieldlen);
-                       if (listlen > 0) BIO_printf(out, "\n");
-                       data += fieldlen;
-                       }
-               }
-
-       return 1;
-       }
+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));
+}
+
+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);
+    }
+}
+
+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)
+        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;
+
+        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)
+{
+    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;
+}