cryptodev_digest_update: don't leak original state->mac_data if realloc fails
[oweals/openssl.git] / crypto / x509v3 / v3_scts.c
index 0868a7bb9220014b14a9601872c6c435f52a5b74..3bf1579310df1703e821e543b94ffd966cf82af7 100644 (file)
 #include <stdio.h>
 #include "cryptlib.h"
 #include <openssl/asn1.h>
-#include "o_time.h"
 #include <openssl/x509v3.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
 
-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},
+#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)++))))
 
-{ 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},
-};
+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;
 
-/* <ripped>
- * from crypto/asn1/t_x509.c
- */
-static const char *mon[12]=
-    {
-    "Jan","Feb","Mar","Apr","May","Jun",
-    "Jul","Aug","Sep","Oct","Nov","Dec"
-    };
-/* </ripped> */
+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);
 
-/* <ripped>
- * 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}
-};
+const X509V3_EXT_METHOD v3_ct_scts[] = {
+{ 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},
 
-static tls12_lookup tls12_sig[] = {
-       {EVP_PKEY_RSA, TLSEXT_signature_rsa},
-       {EVP_PKEY_DSA, TLSEXT_signature_dsa},
-       {EVP_PKEY_EC, TLSEXT_signature_ecdsa}
+{ 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 int tls12_find_nid(int id, tls12_lookup *table, size_t tlen)
+static void tls12_signature_print(BIO *out, const unsigned char hash_alg,
+                                 const unsigned char sig_alg)
        {
-       size_t i;
-       for (i = 0; i < tlen; i++)
+       int nid = NID_undef;
+       /* RFC6962 only permits two signature algorithms */
+       if (hash_alg == TLSEXT_hash_sha256)
                {
-               if ((table[i].id) == id)
-                       return table[i].nid;
+               if (sig_alg == TLSEXT_signature_rsa)
+                       nid = NID_sha256WithRSAEncryption;
+               else if (sig_alg == TLSEXT_signature_ecdsa)
+                       nid = NID_ecdsa_with_SHA256;
                }
-       return NID_undef;
+       if (nid == NID_undef)
+               BIO_printf(out, "%02X%02X", hash_alg, sig_alg);
+       else
+               BIO_printf(out, "%s", OBJ_nid2ln(nid));
        }
 
-/* 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)
+static void timestamp_print(BIO *out, SCT_TIMESTAMP timestamp)
        {
-       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)
+       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 (sign_nid && hash_nid)
-                       OBJ_find_sigid_by_algs(psignhash_nid,
-                                                       hash_nid, sign_nid);
-               else
-                       *psignhash_nid = NID_undef;
+               if (sct->sct) OPENSSL_free(sct->sct);
+               OPENSSL_free(sct);
                }
        }
-/* </ripped> */
 
+static void SCT_LIST_free(STACK_OF(SCT) *a)
+       {
+       sk_SCT_pop_free(a, SCT_free);
+       }
 
-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, fieldlen, linelen;
-       int signhash_nid;
-       time_t unix_epoch = 0;
-       struct tm tm1;
+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) {
+       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;
 
-               if (*data == 0) {       /* v1 SCT */
+               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;
@@ -194,79 +234,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%*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);
+                       sct->logid = p2;
+                       sct->logidlen = 32;
+                       p2 += 32;
+
+                       n2l8(p2, sct->timestamp);
+
+                       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, "");
-                       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
+                        * (1 byte)       Hash algorithm
+                        * (1 byte)       Signature algorithm
+                        * (2 bytes + ?)  Signature
                         */
                        if (sctlen < 4)
-                               return 0;
+                               goto err;
                        sctlen -= 4;
 
-                       tls1_lookup_sigalg(NULL, NULL, &signhash_nid, data);
-                       data += 2;
-                       n2s(data, fieldlen);
+                       sct->hash_alg = *p2++;
+                       sct->sig_alg = *p2++;
+                       n2s(p2, 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;
+                               goto err;
+                       sct->sig = p2;
+                       sct->siglen = fieldlen;
                        }
-
-                       BIO_printf(out, "\n");
                }
+
+       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;
-}
+       }