1 | /* |
2 | * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved. |
3 | * |
4 | * Licensed under the Apache License 2.0 (the "License"). You may not use |
5 | * this file except in compliance with the License. You can obtain a copy |
6 | * in the file LICENSE in the source distribution or at |
7 | * https://www.openssl.org/source/license.html |
8 | */ |
9 | |
10 | #include <string.h> |
11 | |
12 | #include <openssl/ct.h> |
13 | #include <openssl/err.h> |
14 | #include <openssl/evp.h> |
15 | #include <openssl/x509.h> |
16 | |
17 | #include "ct_local.h" |
18 | |
19 | typedef enum sct_signature_type_t { |
20 | SIGNATURE_TYPE_NOT_SET = -1, |
21 | SIGNATURE_TYPE_CERT_TIMESTAMP, |
22 | SIGNATURE_TYPE_TREE_HASH |
23 | } SCT_SIGNATURE_TYPE; |
24 | |
25 | /* |
26 | * Update encoding for SCT signature verification/generation to supplied |
27 | * EVP_MD_CTX. |
28 | */ |
29 | static int sct_ctx_update(EVP_MD_CTX *ctx, const SCT_CTX *sctx, const SCT *sct) |
30 | { |
31 | unsigned char tmpbuf[12]; |
32 | unsigned char *p, *der; |
33 | size_t derlen; |
34 | /*+ |
35 | * digitally-signed struct { |
36 | * (1 byte) Version sct_version; |
37 | * (1 byte) SignatureType signature_type = certificate_timestamp; |
38 | * (8 bytes) uint64 timestamp; |
39 | * (2 bytes) LogEntryType entry_type; |
40 | * (? bytes) select(entry_type) { |
41 | * case x509_entry: ASN.1Cert; |
42 | * case precert_entry: PreCert; |
43 | * } signed_entry; |
44 | * (2 bytes + sct->ext_len) CtExtensions extensions; |
45 | * } |
46 | */ |
47 | if (sct->entry_type == CT_LOG_ENTRY_TYPE_NOT_SET) |
48 | return 0; |
49 | if (sct->entry_type == CT_LOG_ENTRY_TYPE_PRECERT && sctx->ihash == NULL) |
50 | return 0; |
51 | |
52 | p = tmpbuf; |
53 | *p++ = sct->version; |
54 | *p++ = SIGNATURE_TYPE_CERT_TIMESTAMP; |
55 | l2n8(sct->timestamp, p); |
56 | s2n(sct->entry_type, p); |
57 | |
58 | if (!EVP_DigestUpdate(ctx, tmpbuf, p - tmpbuf)) |
59 | return 0; |
60 | |
61 | if (sct->entry_type == CT_LOG_ENTRY_TYPE_X509) { |
62 | der = sctx->certder; |
63 | derlen = sctx->certderlen; |
64 | } else { |
65 | if (!EVP_DigestUpdate(ctx, sctx->ihash, sctx->ihashlen)) |
66 | return 0; |
67 | der = sctx->preder; |
68 | derlen = sctx->prederlen; |
69 | } |
70 | |
71 | /* If no encoding available, fatal error */ |
72 | if (der == NULL) |
73 | return 0; |
74 | |
75 | /* Include length first */ |
76 | p = tmpbuf; |
77 | l2n3(derlen, p); |
78 | |
79 | if (!EVP_DigestUpdate(ctx, tmpbuf, 3)) |
80 | return 0; |
81 | if (!EVP_DigestUpdate(ctx, der, derlen)) |
82 | return 0; |
83 | |
84 | /* Add any extensions */ |
85 | p = tmpbuf; |
86 | s2n(sct->ext_len, p); |
87 | if (!EVP_DigestUpdate(ctx, tmpbuf, 2)) |
88 | return 0; |
89 | |
90 | if (sct->ext_len && !EVP_DigestUpdate(ctx, sct->ext, sct->ext_len)) |
91 | return 0; |
92 | |
93 | return 1; |
94 | } |
95 | |
96 | int SCT_CTX_verify(const SCT_CTX *sctx, const SCT *sct) |
97 | { |
98 | EVP_MD_CTX *ctx = NULL; |
99 | int ret = 0; |
100 | |
101 | if (!SCT_is_complete(sct) || sctx->pkey == NULL || |
102 | sct->entry_type == CT_LOG_ENTRY_TYPE_NOT_SET || |
103 | (sct->entry_type == CT_LOG_ENTRY_TYPE_PRECERT && sctx->ihash == NULL)) { |
104 | CTerr(CT_F_SCT_CTX_VERIFY, CT_R_SCT_NOT_SET); |
105 | return 0; |
106 | } |
107 | if (sct->version != SCT_VERSION_V1) { |
108 | CTerr(CT_F_SCT_CTX_VERIFY, CT_R_SCT_UNSUPPORTED_VERSION); |
109 | return 0; |
110 | } |
111 | if (sct->log_id_len != sctx->pkeyhashlen || |
112 | memcmp(sct->log_id, sctx->pkeyhash, sctx->pkeyhashlen) != 0) { |
113 | CTerr(CT_F_SCT_CTX_VERIFY, CT_R_SCT_LOG_ID_MISMATCH); |
114 | return 0; |
115 | } |
116 | if (sct->timestamp > sctx->epoch_time_in_ms) { |
117 | CTerr(CT_F_SCT_CTX_VERIFY, CT_R_SCT_FUTURE_TIMESTAMP); |
118 | return 0; |
119 | } |
120 | |
121 | ctx = EVP_MD_CTX_new(); |
122 | if (ctx == NULL) |
123 | goto end; |
124 | |
125 | if (!EVP_DigestVerifyInit(ctx, NULL, EVP_sha256(), NULL, sctx->pkey)) |
126 | goto end; |
127 | |
128 | if (!sct_ctx_update(ctx, sctx, sct)) |
129 | goto end; |
130 | |
131 | /* Verify signature */ |
132 | ret = EVP_DigestVerifyFinal(ctx, sct->sig, sct->sig_len); |
133 | /* If ret < 0 some other error: fall through without setting error */ |
134 | if (ret == 0) |
135 | CTerr(CT_F_SCT_CTX_VERIFY, CT_R_SCT_INVALID_SIGNATURE); |
136 | |
137 | end: |
138 | EVP_MD_CTX_free(ctx); |
139 | return ret; |
140 | } |
141 | |