From 5ad29c54082ae0e00f389b2373c7ca065d3860ad Mon Sep 17 00:00:00 2001 From: Adam Eijdenberg Date: Fri, 4 Dec 2015 10:49:14 -0800 Subject: Add more CT utility routines to be used as part of larger patch. Reviewed-by: Ben Laurie Reviewed-by: Rich Salz --- crypto/ct/Makefile.in | 4 +- crypto/ct/ct_err.c | 19 +- crypto/ct/ct_lib.c | 72 ++++++- crypto/ct/ct_oct.c | 535 ++++++++++++++++++++++++++++++++++++++++++++++++++ crypto/ct/ct_prn.c | 129 ++++++++++++ 5 files changed, 755 insertions(+), 4 deletions(-) create mode 100644 crypto/ct/ct_oct.c create mode 100644 crypto/ct/ct_prn.c (limited to 'crypto/ct') diff --git a/crypto/ct/Makefile.in b/crypto/ct/Makefile.in index 100179ddfa..7e58c3b237 100644 --- a/crypto/ct/Makefile.in +++ b/crypto/ct/Makefile.in @@ -15,8 +15,8 @@ CFLAGS= $(INCLUDES) $(CFLAG) $(SHARED_CFLAG) GENERAL=Makefile LIB=$(TOP)/libcrypto.a -LIBSRC= ct_lib.c ct_err.c -LIBOBJ= ct_lib.o ct_err.o +LIBSRC= ct_lib.c ct_err.c ct_oct.c ct_prn.c +LIBOBJ= ct_lib.o ct_err.o ct_oct.o ct_prn.o SRC= $(LIBSRC) diff --git a/crypto/ct/ct_err.c b/crypto/ct/ct_err.c index 1657764617..b2ba432e24 100644 --- a/crypto/ct/ct_err.c +++ b/crypto/ct/ct_err.c @@ -1,5 +1,6 @@ +/* ct_err.c */ /* ==================================================================== - * Copyright (c) 1999-2015 The OpenSSL Project. All rights reserved. + * Copyright (c) 1999-2016 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -69,16 +70,32 @@ # define ERR_REASON(reason) ERR_PACK(ERR_LIB_CT,0,reason) static ERR_STRING_DATA CT_str_functs[] = { + {ERR_FUNC(CT_F_D2I_SCT_LIST), "d2i_SCT_LIST"}, + {ERR_FUNC(CT_F_I2D_SCT_LIST), "i2d_SCT_LIST"}, + {ERR_FUNC(CT_F_I2O_SCT), "i2o_SCT"}, + {ERR_FUNC(CT_F_I2O_SCT_LIST), "i2o_SCT_LIST"}, + {ERR_FUNC(CT_F_I2O_SCT_SIGNATURE), "i2o_SCT_signature"}, + {ERR_FUNC(CT_F_O2I_SCT), "o2i_SCT"}, + {ERR_FUNC(CT_F_O2I_SCT_LIST), "o2i_SCT_LIST"}, + {ERR_FUNC(CT_F_O2I_SCT_SIGNATURE), "o2i_SCT_signature"}, {ERR_FUNC(CT_F_SCT_NEW), "SCT_new"}, {ERR_FUNC(CT_F_SCT_SET0_LOG_ID), "SCT_set0_log_id"}, + {ERR_FUNC(CT_F_SCT_SET1_EXTENSIONS), "SCT_set1_extensions"}, + {ERR_FUNC(CT_F_SCT_SET1_LOG_ID), "SCT_set1_log_id"}, + {ERR_FUNC(CT_F_SCT_SET1_SIGNATURE), "SCT_set1_signature"}, {ERR_FUNC(CT_F_SCT_SET_LOG_ENTRY_TYPE), "SCT_set_log_entry_type"}, {ERR_FUNC(CT_F_SCT_SET_SIGNATURE_NID), "SCT_set_signature_nid"}, {ERR_FUNC(CT_F_SCT_SET_VERSION), "SCT_set_version"}, + {ERR_FUNC(CT_F_SCT_SIGNATURE_IS_VALID), "SCT_signature_is_valid"}, {0, NULL} }; static ERR_STRING_DATA CT_str_reasons[] = { {ERR_REASON(CT_R_INVALID_LOG_ID_LENGTH), "invalid log id length"}, + {ERR_REASON(CT_R_SCT_INVALID), "sct invalid"}, + {ERR_REASON(CT_R_SCT_INVALID_SIGNATURE), "sct invalid signature"}, + {ERR_REASON(CT_R_SCT_LIST_INVALID), "sct list invalid"}, + {ERR_REASON(CT_R_SCT_NOT_SET), "sct not set"}, {ERR_REASON(CT_R_UNRECOGNIZED_SIGNATURE_NID), "unrecognized signature nid"}, {ERR_REASON(CT_R_UNSUPPORTED_ENTRY_TYPE), "unsupported entry type"}, diff --git a/crypto/ct/ct_lib.c b/crypto/ct/ct_lib.c index d1ec85d86c..81676e306f 100644 --- a/crypto/ct/ct_lib.c +++ b/crypto/ct/ct_lib.c @@ -77,7 +77,7 @@ SCT *SCT_new(void) void SCT_free(SCT *sct) { - if (sct) { + if (sct != NULL) { OPENSSL_free(sct->log_id); OPENSSL_free(sct->ext); OPENSSL_free(sct->sig); @@ -119,6 +119,31 @@ int SCT_set0_log_id(SCT *sct, unsigned char *log_id, size_t log_id_len) return 1; } +int SCT_set1_log_id(SCT *sct, const unsigned char *log_id, size_t log_id_len) +{ + /* Currently only SHA-256 allowed so length must be SCT_V1_HASHLEN */ + if (log_id_len != SCT_V1_HASHLEN) { + CTerr(CT_F_SCT_SET1_LOG_ID, CT_R_INVALID_LOG_ID_LENGTH); + return 0; + } + + OPENSSL_free(sct->log_id); + if (log_id == NULL || log_id_len == 0) { + sct->log_id = NULL; + } else { + sct->log_id = OPENSSL_memdup(log_id, log_id_len); + + if (sct->log_id == NULL) { + CTerr(CT_F_SCT_SET1_LOG_ID, ERR_R_MALLOC_FAILURE); + return 0; + } + } + + sct->log_id_len = log_id_len; + return 1; +} + + void SCT_set_timestamp(SCT *sct, uint64_t timestamp) { sct->timestamp = timestamp; @@ -148,6 +173,23 @@ void SCT_set0_extensions(SCT *sct, unsigned char *ext, size_t ext_len) sct->ext_len = ext_len; } +int SCT_set1_extensions(SCT *sct, const unsigned char *ext, size_t ext_len) +{ + OPENSSL_free(sct->ext); + sct->ext = NULL; + sct->ext_len = 0; + + if (ext != NULL && ext_len > 0) { + sct->ext = OPENSSL_memdup(ext, ext_len); + if (sct->ext == NULL) { + CTerr(CT_F_SCT_SET1_EXTENSIONS, ERR_R_MALLOC_FAILURE); + return 0; + } + sct->ext_len = ext_len; + } + return 1; +} + void SCT_set0_signature(SCT *sct, unsigned char *sig, size_t sig_len) { OPENSSL_free(sct->sig); @@ -155,6 +197,22 @@ void SCT_set0_signature(SCT *sct, unsigned char *sig, size_t sig_len) sct->sig_len = sig_len; } +int SCT_set1_signature(SCT *sct, const unsigned char *sig, size_t sig_len) +{ + OPENSSL_free(sct->sig); + if (sig == NULL || sig_len == 0) { + sct->sig = NULL; + } else { + sct->sig = OPENSSL_memdup(sig, sig_len); + if (sct->sig == NULL) { + CTerr(CT_F_SCT_SET1_SIGNATURE, ERR_R_MALLOC_FAILURE); + return 0; + } + } + sct->sig_len = sig_len; + return 1; +} + sct_version_t SCT_get_version(const SCT *sct) { return sct->version; @@ -205,4 +263,16 @@ size_t SCT_get0_signature(const SCT *sct, unsigned char **sig) return sct->sig_len; } +int SCT_is_valid(const SCT *sct) +{ + switch (sct->version) { + case UNSET_VERSION: + return 0; + case SCT_V1: + return sct->log_id != NULL && SCT_signature_is_valid(sct); + default: + return sct->sct != NULL; /* Just need cached encoding */ + } +} + #endif diff --git a/crypto/ct/ct_oct.c b/crypto/ct/ct_oct.c new file mode 100644 index 0000000000..8d075fcb88 --- /dev/null +++ b/crypto/ct/ct_oct.c @@ -0,0 +1,535 @@ +/* + * Written by Rob Stradling (rob@comodo.com) and Stephen Henson + * (steve@openssl.org) for the OpenSSL project 2014. + */ +/* ==================================================================== + * Copyright (c) 2014 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * 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 + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#ifndef OPENSSL_NO_CT + +# include +# include "internal/cryptlib.h" +# include +# include +# include +# include +# include "crypto/include/internal/ct_int.h" + +# define n2s(c,s) ((s=(((unsigned int)((c)[0]))<< 8)| \ + (((unsigned int)((c)[1])) )),c+=2) + +# define s2n(s,c) ((c[0]=(unsigned char)(((s)>> 8)&0xff), \ + c[1]=(unsigned char)(((s) )&0xff)),c+=2) + +# define n2l8(c,l) (l =((uint64_t)(*((c)++)))<<56, \ + l|=((uint64_t)(*((c)++)))<<48, \ + l|=((uint64_t)(*((c)++)))<<40, \ + l|=((uint64_t)(*((c)++)))<<32, \ + l|=((uint64_t)(*((c)++)))<<24, \ + l|=((uint64_t)(*((c)++)))<<16, \ + l|=((uint64_t)(*((c)++)))<< 8, \ + l|=((uint64_t)(*((c)++)))) + +# define l2n8(l,c) (*((c)++)=(unsigned char)(((l)>>56)&0xff), \ + *((c)++)=(unsigned char)(((l)>>48)&0xff), \ + *((c)++)=(unsigned char)(((l)>>40)&0xff), \ + *((c)++)=(unsigned char)(((l)>>32)&0xff), \ + *((c)++)=(unsigned char)(((l)>>24)&0xff), \ + *((c)++)=(unsigned char)(((l)>>16)&0xff), \ + *((c)++)=(unsigned char)(((l)>> 8)&0xff), \ + *((c)++)=(unsigned char)(((l) )&0xff)) + +static STACK_OF(SCT) *d2i_SCT_LIST(STACK_OF(SCT) **a, + const unsigned char **pp, int len); +static int i2d_SCT_LIST(STACK_OF(SCT) *a, unsigned char **pp); +static int i2r_SCT_LIST(X509V3_EXT_METHOD *method, STACK_OF(SCT) *sct_list, + BIO *out, int indent); + +static char *i2s_poison(const X509V3_EXT_METHOD *method, void *val) +{ + return OPENSSL_strdup("NULL"); +} + +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, (X509V3_EXT_I2D)i2d_SCT_LIST, + 0, 0, 0, 0, + (X509V3_EXT_I2R)i2r_SCT_LIST, 0, + NULL }, + + { NID_ct_precert_poison, 0, ASN1_ITEM_ref(ASN1_NULL), + 0, 0, 0, 0, i2s_poison, 0, + 0, 0, 0, 0, NULL }, + + { NID_ct_cert_scts, 0, NULL, + 0, (X509V3_EXT_FREE)SCT_LIST_free, + (X509V3_EXT_D2I)d2i_SCT_LIST, (X509V3_EXT_I2D)i2d_SCT_LIST, + 0, 0, 0, 0, + (X509V3_EXT_I2R)i2r_SCT_LIST, 0, + NULL }, +}; + +int SCT_signature_is_valid(const SCT *sct) +{ + if (SCT_get_signature_nid(sct) == NID_undef || + sct->sig_len == 0 || sct->sig == NULL) { + return 0; + } + + return 1; +} + + +int o2i_SCT_signature(SCT *sct, const unsigned char **in, size_t len) +{ + size_t siglen; + size_t len_remaining = len; + const unsigned char *p = *in; + + if (sct->version != SCT_V1) { + CTerr(CT_F_O2I_SCT_SIGNATURE, CT_R_UNSUPPORTED_VERSION); + return -1; + } + /* + * digitally-signed struct header: (1 byte) Hash algorithm (1 byte) + * Signature algorithm (2 bytes + ?) Signature + * + * This explicitly rejects empty signatures: they're invalid for + * all supported algorithms. + */ + if (len <= 4) { + CTerr(CT_F_O2I_SCT_SIGNATURE, CT_R_SCT_INVALID_SIGNATURE); + return -1; + } + + /* Get hash and signature algorithm */ + sct->hash_alg = *p++; + sct->sig_alg = *p++; + if (SCT_get_signature_nid(sct) == NID_undef) { + CTerr(CT_F_O2I_SCT_SIGNATURE, CT_R_SCT_INVALID_SIGNATURE); + return -1; + } + /* Retrieve signature and check it is consistent with the buffer length */ + n2s(p, siglen); + len_remaining -= (p - *in); + if (siglen > len_remaining) { + CTerr(CT_F_O2I_SCT_SIGNATURE, CT_R_SCT_INVALID_SIGNATURE); + return -1; + } + + if (SCT_set1_signature(sct, p, siglen) != 1) + return -1; + len_remaining -= siglen; + *in = p + siglen; + + return len - len_remaining; +} + +SCT *o2i_SCT(SCT **psct, const unsigned char **in, size_t len) +{ + SCT *sct = NULL; + const unsigned char *p; + + if (len == 0 || len > MAX_SCT_SIZE) { + CTerr(CT_F_O2I_SCT, CT_R_SCT_INVALID); + goto err; + } + + if ((sct = SCT_new()) == NULL) + goto err; + + p = *in; + + sct->version = *p; + if (sct->version == SCT_V1) { + int sig_len; + size_t len2; + /* + * Fixed-length header: struct { (1 byte) Version sct_version; (32 + * bytes) log_id id; (8 bytes) uint64 timestamp; (2 bytes + ?) + * CtExtensions extensions; + */ + if (len < 43) { + CTerr(CT_F_O2I_SCT, CT_R_SCT_INVALID); + goto err; + } + len -= 43; + p++; + sct->log_id = BUF_memdup(p, SCT_V1_HASHLEN); + if (sct->log_id == NULL) + goto err; + sct->log_id_len = SCT_V1_HASHLEN; + p += SCT_V1_HASHLEN; + + n2l8(p, sct->timestamp); + + n2s(p, len2); + if (len < len2) { + CTerr(CT_F_O2I_SCT, CT_R_SCT_INVALID); + goto err; + } + if (len2 > 0) { + sct->ext = BUF_memdup(p, len2); + if (sct->ext == NULL) + goto err; + } + sct->ext_len = len2; + p += len2; + len -= len2; + + sig_len = o2i_SCT_signature(sct, &p, len); + if (sig_len <= 0) { + CTerr(CT_F_O2I_SCT, CT_R_SCT_INVALID); + goto err; + } + len -= sig_len; + *in = p + len; + } else { + /* If not V1 just cache encoding */ + sct->sct = BUF_memdup(p, len); + if (sct->sct == NULL) + goto err; + sct->sct_len = len; + *in = p + len; + } + + if (psct != NULL) { + SCT_free(*psct); + *psct = sct; + } + + return sct; +err: + SCT_free(sct); + return NULL; +} + +int i2o_SCT_signature(const SCT *sct, unsigned char **out) +{ + size_t len; + unsigned char *p = NULL; + + if (!SCT_signature_is_valid(sct)) { + CTerr(CT_F_I2O_SCT_SIGNATURE, CT_R_SCT_INVALID_SIGNATURE); + goto err; + } + + if (sct->version != SCT_V1) { + CTerr(CT_F_I2O_SCT_SIGNATURE, CT_R_UNSUPPORTED_VERSION); + goto err; + } + + /* + * (1 byte) Hash algorithm + * (1 byte) Signature algorithm + * (2 bytes + ?) Signature + */ + len = 4 + sct->sig_len; + + if (out != NULL) { + if (*out != NULL) { + p = *out; + *out += len; + } else { + p = OPENSSL_malloc(len); + if (p == NULL) { + CTerr(CT_F_I2O_SCT_SIGNATURE, ERR_R_MALLOC_FAILURE); + goto err; + } + *out = p; + } + + *p++ = sct->hash_alg; + *p++ = sct->sig_alg; + s2n(sct->sig_len, p); + memcpy(p, sct->sig, sct->sig_len); + } + + return len; +err: + OPENSSL_free(p); + return -1; +} + +int i2o_SCT(const SCT *sct, unsigned char **out) +{ + size_t len; + unsigned char *p = NULL; + + if (!SCT_is_valid(sct)) { + CTerr(CT_F_I2O_SCT, CT_R_SCT_NOT_SET); + goto err; + } + /* + * Fixed-length header: struct { (1 byte) Version sct_version; (32 bytes) + * log_id id; (8 bytes) uint64 timestamp; (2 bytes + ?) CtExtensions + * extensions; (1 byte) Hash algorithm (1 byte) Signature algorithm (2 + * bytes + ?) Signature + */ + if (sct->version == SCT_V1) + len = 43 + sct->ext_len + 4 + sct->sig_len; + else + len = sct->sct_len; + + if (out == NULL) + return len; + + if (*out != NULL) { + p = *out; + *out += len; + } else { + p = OPENSSL_malloc(len); + if (p == NULL) { + CTerr(CT_F_I2O_SCT, ERR_R_MALLOC_FAILURE); + goto err; + } + *out = p; + } + + if (sct->version == SCT_V1) { + *p++ = sct->version; + memcpy(p, sct->log_id, SCT_V1_HASHLEN); + p += SCT_V1_HASHLEN; + l2n8(sct->timestamp, p); + s2n(sct->ext_len, p); + if (sct->ext_len > 0) { + memcpy(p, sct->ext, sct->ext_len); + p += sct->ext_len; + } + if (i2o_SCT_signature(sct, &p) <= 0) + goto err; + } else { + memcpy(p, sct->sct, len); + } + + return len; +err: + OPENSSL_free(p); + return -1; +} + +void SCT_LIST_free(STACK_OF(SCT) *a) +{ + sk_SCT_pop_free(a, SCT_free); +} + +STACK_OF(SCT) *o2i_SCT_LIST(STACK_OF(SCT) **a, const unsigned char **pp, + size_t len) +{ + STACK_OF(SCT) *sk = NULL; + size_t list_len, sct_len; + + if (len < 2 || len > MAX_SCT_LIST_SIZE) { + CTerr(CT_F_O2I_SCT_LIST, CT_R_SCT_LIST_INVALID); + return NULL; + } + + n2s(*pp, list_len); + if (list_len != len - 2) { + CTerr(CT_F_O2I_SCT_LIST, CT_R_SCT_LIST_INVALID); + return NULL; + } + + if (a == NULL || *a == NULL) { + sk = sk_SCT_new_null(); + if (sk == NULL) + return NULL; + } else { + SCT *sct; + + /* Use the given stack, but empty it first. */ + sk = *a; + while ((sct = sk_SCT_pop(sk)) != NULL) + SCT_free(sct); + } + + while (list_len > 0) { + SCT *sct; + + if (list_len < 2) { + CTerr(CT_F_O2I_SCT_LIST, CT_R_SCT_LIST_INVALID); + goto err; + } + n2s(*pp, sct_len); + list_len -= 2; + + if (sct_len == 0 || sct_len > list_len) { + CTerr(CT_F_O2I_SCT_LIST, CT_R_SCT_LIST_INVALID); + goto err; + } + list_len -= sct_len; + + if ((sct = o2i_SCT(NULL, pp, sct_len)) == NULL) + goto err; + if (!sk_SCT_push(sk, sct)) { + SCT_free(sct); + goto err; + } + } + + if (a != NULL && *a == NULL) + *a = sk; + return sk; + + err: + if (a == NULL || *a == NULL) + SCT_LIST_free(sk); + return NULL; +} + +int i2o_SCT_LIST(STACK_OF(SCT) *a, unsigned char **pp) +{ + int len, sct_len, i, is_pp_new = 0; + size_t len2; + unsigned char *p = NULL, *p2; + + if (pp != NULL) { + if (*pp == NULL) { + if ((len = i2o_SCT_LIST(a, NULL)) == -1) { + CTerr(CT_F_I2O_SCT_LIST, CT_R_SCT_LIST_INVALID); + return -1; + } + if ((*pp = OPENSSL_malloc(len)) == NULL) { + CTerr(CT_F_I2O_SCT_LIST, ERR_R_MALLOC_FAILURE); + return -1; + } + is_pp_new = 1; + } + p = *pp + 2; + } + + len2 = 2; + for (i = 0; i < sk_SCT_num(a); i++) { + if (pp != NULL) { + p2 = p; + p += 2; + if ((sct_len = i2o_SCT(sk_SCT_value(a, i), &p)) == -1) + goto err; + s2n(sct_len, p2); + } else { + if ((sct_len = i2o_SCT(sk_SCT_value(a, i), NULL)) == -1) + goto err; + } + len2 += 2 + sct_len; + } + + if (len2 > MAX_SCT_LIST_SIZE) + goto err; + + if (pp != NULL) { + p = *pp; + s2n(len2 - 2, p); + } + if (!is_pp_new) + *pp += len2; + return len2; + + err: + if (is_pp_new) { + OPENSSL_free(*pp); + *pp = NULL; + } + return -1; +} + +static STACK_OF(SCT) *d2i_SCT_LIST(STACK_OF(SCT) **a, + const unsigned char **pp, int len) +{ + ASN1_OCTET_STRING *oct = NULL; + STACK_OF(SCT) *sk = NULL; + const unsigned char *p; + + p = *pp; + if (d2i_ASN1_OCTET_STRING(&oct, &p, len) == NULL) + return NULL; + + p = oct->data; + if ((sk = o2i_SCT_LIST(a, &p, oct->length)) != NULL) + *pp += len; + + ASN1_OCTET_STRING_free(oct); + return sk; +} + +static int i2d_SCT_LIST(STACK_OF(SCT) *a, unsigned char **out) +{ + ASN1_OCTET_STRING oct; + int len; + + oct.data = NULL; + if ((oct.length = i2o_SCT_LIST(a, &oct.data)) == -1) + return -1; + + len = i2d_ASN1_OCTET_STRING(&oct, out); + OPENSSL_free(oct.data); + return len; +} + +static int i2r_SCT_LIST(X509V3_EXT_METHOD *method, STACK_OF(SCT) *sct_list, + BIO *out, int indent) +{ + int i; + + for (i = 0; i < sk_SCT_num(sct_list); ++i) { + SCT *sct = sk_SCT_value(sct_list, i); + SCT_print(sct, out, indent); + if (i < sk_SCT_num(sct_list) - 1) + BIO_printf(out, "\n"); + } + + return 1; +} + +#endif diff --git a/crypto/ct/ct_prn.c b/crypto/ct/ct_prn.c new file mode 100644 index 0000000000..91325537dd --- /dev/null +++ b/crypto/ct/ct_prn.c @@ -0,0 +1,129 @@ +/* + * Written by Rob Stradling (rob@comodo.com) and Stephen Henson + * (steve@openssl.org) for the OpenSSL project 2014. + */ +/* ==================================================================== + * Copyright (c) 2014 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * 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 + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#ifndef OPENSSL_NO_CT + +# include +# include "internal/cryptlib.h" +# include +# include +# include +# include +# include "crypto/include/internal/ct_int.h" + +static void sct_sigalg_print(BIO *out, const SCT *sct) +{ + int nid = SCT_get_signature_nid(sct); + + if (nid <= 0) + BIO_printf(out, "%02X%02X", sct->hash_alg, sct->sig_alg); + else + BIO_printf(out, "%s", OBJ_nid2ln(nid)); +} + +static void timestamp_print(BIO *out, uint64_t timestamp) +{ + ASN1_GENERALIZEDTIME *gen = ASN1_GENERALIZEDTIME_new(); + char genstr[20]; + + 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); +} + +void SCT_print(SCT *sct, BIO *out, int indent) +{ + BIO_printf(out, "%*sSigned Certificate Timestamp:", indent, ""); + BIO_printf(out, "\n%*sVersion : ", indent + 4, ""); + + if (sct->version != SCT_V1) { + BIO_printf(out, "unknown\n%*s", indent + 16, ""); + BIO_hex_string(out, indent + 16, 16, sct->sct, sct->sct_len); + return; + } + + BIO_printf(out, "v1 (0x0)"); + + BIO_printf(out, "\n%*sLog ID : ", indent + 4, ""); + BIO_hex_string(out, indent + 16, 16, sct->log_id, sct->log_id_len); + + BIO_printf(out, "\n%*sTimestamp : ", indent + 4, ""); + timestamp_print(out, sct->timestamp); + + BIO_printf(out, "\n%*sExtensions: ", indent + 4, ""); + if (sct->ext_len == 0) + BIO_printf(out, "none"); + else + BIO_hex_string(out, indent + 16, 16, sct->ext, sct->ext_len); + + BIO_printf(out, "\n%*sSignature : ", indent + 4, ""); + sct_sigalg_print(out, sct); + BIO_printf(out, "\n%*s ", indent + 4, ""); + BIO_hex_string(out, indent + 16, 16, sct->sig, sct->sig_len); +} + +#endif -- cgit v1.2.3