Separate the SCT List parser from the SCT List viewer
[openssl.git] / crypto / x509v3 / v3_scts.c
1 /* v3_scts.c */
2 /* Written by Rob Stradling (rob@comodo.com) for the OpenSSL project 2014.
3  */
4 /* ====================================================================
5  * Copyright (c) 2014 The OpenSSL Project.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer. 
13  *
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in
16  *    the documentation and/or other materials provided with the
17  *    distribution.
18  *
19  * 3. All advertising materials mentioning features or use of this
20  *    software must display the following acknowledgment:
21  *    "This product includes software developed by the OpenSSL Project
22  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
23  *
24  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
25  *    endorse or promote products derived from this software without
26  *    prior written permission. For written permission, please contact
27  *    licensing@OpenSSL.org.
28  *
29  * 5. Products derived from this software may not be called "OpenSSL"
30  *    nor may "OpenSSL" appear in their names without prior written
31  *    permission of the OpenSSL Project.
32  *
33  * 6. Redistributions of any form whatsoever must retain the following
34  *    acknowledgment:
35  *    "This product includes software developed by the OpenSSL Project
36  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
37  *
38  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
39  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
41  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
42  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
43  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
44  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
45  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
46  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
47  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
48  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
49  * OF THE POSSIBILITY OF SUCH DAMAGE.
50  * ====================================================================
51  *
52  * This product includes cryptographic software written by Eric Young
53  * (eay@cryptsoft.com).  This product includes software written by Tim
54  * Hudson (tjh@cryptsoft.com).
55  *
56  */
57
58
59 #include <stdio.h>
60 #include "cryptlib.h"
61 #include <openssl/asn1.h>
62 #include <openssl/x509v3.h>
63 #include "../ssl/ssl_locl.h"
64
65 #if (defined(_WIN32) || defined(_WIN64)) && !defined(__MINGW32__)
66 #define SCT_TIMESTAMP unsigned __int64
67 #elif defined(__arch64__)
68 #define SCT_TIMESTAMP unsigned long
69 #else
70 #define SCT_TIMESTAMP unsigned long long
71 #endif
72
73 #define n2l8(c,l)       (l =((SCT_TIMESTAMP)(*((c)++)))<<56, \
74                          l|=((SCT_TIMESTAMP)(*((c)++)))<<48, \
75                          l|=((SCT_TIMESTAMP)(*((c)++)))<<40, \
76                          l|=((SCT_TIMESTAMP)(*((c)++)))<<32, \
77                          l|=((SCT_TIMESTAMP)(*((c)++)))<<24, \
78                          l|=((SCT_TIMESTAMP)(*((c)++)))<<16, \
79                          l|=((SCT_TIMESTAMP)(*((c)++)))<< 8, \
80                          l|=((SCT_TIMESTAMP)(*((c)++))))
81
82 typedef struct SCT_st {
83         /* The encoded SCT */
84         unsigned char *sct;
85         unsigned short sctlen;
86
87         /* Components of the SCT.  "logid", "ext" and "sig" point to addresses
88          * inside "sct".
89          */
90         unsigned char version;
91         unsigned char* logid;
92         unsigned short logidlen;
93         SCT_TIMESTAMP timestamp;
94         unsigned char *ext;
95         unsigned short extlen;
96         unsigned char hash_alg;
97         unsigned char sig_alg;
98         unsigned char *sig;
99         unsigned short siglen;
100 } SCT;
101
102 DECLARE_STACK_OF(SCT)
103
104 static void SCT_LIST_free(STACK_OF(SCT) *a);
105 static STACK_OF(SCT) *d2i_SCT_LIST(STACK_OF(SCT) **a, const unsigned char **pp,
106                                    long length);
107 static int i2r_SCT_LIST(X509V3_EXT_METHOD *method, STACK_OF(SCT) *sct_list,
108                         BIO *out, int indent);
109
110 const X509V3_EXT_METHOD v3_ct_scts[] = {
111 { NID_ct_precert_scts, 0, NULL,
112 0,(X509V3_EXT_FREE)SCT_LIST_free,
113 (X509V3_EXT_D2I)d2i_SCT_LIST, 0,
114 0,0,0,0,
115 (X509V3_EXT_I2R)i2r_SCT_LIST, 0,
116 NULL},
117
118 { NID_ct_cert_scts, 0, NULL,
119 0,(X509V3_EXT_FREE)SCT_LIST_free,
120 (X509V3_EXT_D2I)d2i_SCT_LIST, 0,
121 0,0,0,0,
122 (X509V3_EXT_I2R)i2r_SCT_LIST, 0,
123 NULL},
124 };
125
126 static void tls12_signature_print(BIO *out, const unsigned char hash_alg,
127                                   const unsigned char sig_alg)
128         {
129         int nid = NID_undef;
130         /* RFC6962 only permits two signature algorithms */
131         if (hash_alg == TLSEXT_hash_sha256)
132                 {
133                 if (sig_alg == TLSEXT_signature_rsa)
134                         nid = NID_sha256WithRSAEncryption;
135                 else if (sig_alg == TLSEXT_signature_ecdsa)
136                         nid = NID_ecdsa_with_SHA256;
137                 }
138         if (nid == NID_undef)
139                 BIO_printf(out, "%02X%02X", hash_alg, sig_alg);
140         else
141                 BIO_printf(out, "%s", OBJ_nid2ln(nid));
142         }
143
144 static void timestamp_print(BIO *out, SCT_TIMESTAMP timestamp)
145         {
146         ASN1_GENERALIZEDTIME *gen;
147         char genstr[20];
148         gen = ASN1_GENERALIZEDTIME_new();
149         ASN1_GENERALIZEDTIME_adj(gen, (time_t)0,
150                                         (int)(timestamp / 86400000),
151                                         (timestamp % 86400000) / 1000);
152         /* Note GeneralizedTime from ASN1_GENERALIZETIME_adj is always 15
153          * characters long with a final Z. Update it with fractional seconds.
154          */
155         BIO_snprintf(genstr, sizeof(genstr), "%.14s.%03dZ",
156                                 ASN1_STRING_data(gen),
157                                 (unsigned int)(timestamp % 1000));
158         ASN1_GENERALIZEDTIME_set_string(gen, genstr);
159         ASN1_GENERALIZEDTIME_print(out, gen);
160         ASN1_GENERALIZEDTIME_free(gen);
161         }
162
163 static void SCT_free(SCT *sct)
164         {
165         if (sct)
166                 {
167                 if (sct->sct) OPENSSL_free(sct->sct);
168                 OPENSSL_free(sct);
169                 }
170         }
171
172 static void SCT_LIST_free(STACK_OF(SCT) *a)
173         {
174         sk_SCT_pop_free(a, SCT_free);
175         }
176
177 static STACK_OF(SCT) *d2i_SCT_LIST(STACK_OF(SCT) **a, const unsigned char **pp,
178                                    long length)
179         {
180         ASN1_OCTET_STRING *oct = NULL;
181         STACK_OF(SCT) *sk = NULL;
182         SCT *sct;
183         unsigned char *p, *p2;
184         unsigned short listlen, sctlen = 0, fieldlen;
185
186         if (d2i_ASN1_OCTET_STRING(&oct, pp, length) == NULL)
187                 return NULL;
188         if (oct->length < 2)
189                 goto done;
190         p = oct->data;
191         n2s(p, listlen);
192         if (listlen != oct->length - 2)
193                 goto done;
194
195         if ((sk=sk_SCT_new_null()) == NULL)
196                 goto done;
197
198         while (listlen > 0)
199                 {
200                 if (listlen < 2)
201                         goto err;
202                 n2s(p, sctlen);
203                 listlen -= 2;
204
205                 if ((sctlen < 1) || (sctlen > listlen))
206                         goto err;
207                 listlen -= sctlen;
208
209                 sct = OPENSSL_malloc(sizeof(SCT));
210                 if (!sct)
211                         goto err;
212                 if (!sk_SCT_push(sk, sct))
213                         {
214                         OPENSSL_free(sct);
215                         goto err;
216                         }
217
218                 sct->sct = OPENSSL_malloc(sctlen);
219                 if (!sct->sct)
220                         goto err;
221                 memcpy(sct->sct, p, sctlen);
222                 sct->sctlen = sctlen;
223                 p += sctlen;
224                 p2 = sct->sct;
225
226                 sct->version = *p2++;
227                 if (sct->version == 0)          /* SCT v1 */
228                         {
229                         /* Fixed-length header:
230                          *              struct {
231                          * (1 byte)       Version sct_version;
232                          * (32 bytes)     LogID id;
233                          * (8 bytes)      uint64 timestamp;
234                          * (2 bytes + ?)  CtExtensions extensions;
235                          */
236                         if (sctlen < 43)
237                                 goto err;
238                         sctlen -= 43;
239
240                         sct->logid = p2;
241                         sct->logidlen = 32;
242                         p2 += 32;
243
244                         n2l8(p2, sct->timestamp);
245
246                         n2s(p2, fieldlen);
247                         if (sctlen < fieldlen)
248                                 goto err;
249                         sct->ext = p2;
250                         sct->extlen = fieldlen;
251                         p2 += fieldlen;
252                         sctlen -= fieldlen;
253
254                         /* digitally-signed struct header:
255                          * (1 byte)       Hash algorithm
256                          * (1 byte)       Signature algorithm
257                          * (2 bytes + ?)  Signature
258                          */
259                         if (sctlen < 4)
260                                 goto err;
261                         sctlen -= 4;
262
263                         sct->hash_alg = *p2++;
264                         sct->sig_alg = *p2++;
265                         n2s(p2, fieldlen);
266                         if (sctlen != fieldlen)
267                                 goto err;
268                         sct->sig = p2;
269                         sct->siglen = fieldlen;
270                         }
271                 }
272
273         done:
274         ASN1_OCTET_STRING_free(oct);
275         return sk;
276
277         err:
278         SCT_LIST_free(sk);
279         sk = NULL;
280         goto done;
281         }
282
283 static int i2r_SCT_LIST(X509V3_EXT_METHOD *method, STACK_OF(SCT) *sct_list,
284                         BIO *out, int indent)
285         {
286         SCT *sct;
287         int i;
288
289         for (i = 0; i < sk_SCT_num(sct_list);) {
290                 sct = sk_SCT_value(sct_list, i);
291
292                 BIO_printf(out, "%*sSigned Certificate Timestamp:", indent, "");
293                 BIO_printf(out, "\n%*sVersion   : ", indent + 4, "");
294
295                 if (sct->version == 0)  /* SCT v1 */
296                         {
297                         BIO_printf(out, "v1(0)");
298
299                         BIO_printf(out, "\n%*sLog ID    : ", indent + 4, "");
300                         BIO_hex_string(out, indent + 16, 16, sct->logid,
301                                        sct->logidlen);
302
303                         BIO_printf(out, "\n%*sTimestamp : ", indent + 4, "");
304                         timestamp_print(out, sct->timestamp);
305
306                         BIO_printf(out, "\n%*sExtensions: ", indent + 4, "");
307                         if (sct->extlen == 0)
308                                 BIO_printf(out, "none");
309                         else
310                                 BIO_hex_string(out, indent + 16, 16, sct->ext,
311                                                sct->extlen);
312
313                         BIO_printf(out, "\n%*sSignature : ", indent + 4, "");
314                         tls12_signature_print(out, sct->hash_alg, sct->sig_alg);
315                         BIO_printf(out, "\n%*s            ", indent + 4, "");
316                         BIO_hex_string(out, indent + 16, 16, sct->sig,
317                                        sct->siglen);
318                         }
319                 else                    /* Unknown version */
320                         {
321                         BIO_printf(out, "unknown\n%*s", indent + 16, "");
322                         BIO_hex_string(out, indent + 16, 16, sct->sct,
323                                        sct->sctlen);
324                         }
325
326                 if (++i < sk_SCT_num(sct_list)) BIO_printf(out, "\n");
327                 }
328
329         return 1;
330         }