xref: /dragonfly/crypto/libressl/crypto/ct/ct_b64.c (revision 6f5ec8b5)
1 /*	$OpenBSD: ct_b64.c,v 1.6 2021/12/20 17:19:19 jsing Exp $ */
2 /*
3  * Written by Rob Stradling (rob@comodo.com) and Stephen Henson
4  * (steve@openssl.org) for the OpenSSL project 2014.
5  */
6 /* ====================================================================
7  * Copyright (c) 2014 The OpenSSL Project.  All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in
18  *    the documentation and/or other materials provided with the
19  *    distribution.
20  *
21  * 3. All advertising materials mentioning features or use of this
22  *    software must display the following acknowledgment:
23  *    "This product includes software developed by the OpenSSL Project
24  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
25  *
26  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
27  *    endorse or promote products derived from this software without
28  *    prior written permission. For written permission, please contact
29  *    licensing@OpenSSL.org.
30  *
31  * 5. Products derived from this software may not be called "OpenSSL"
32  *    nor may "OpenSSL" appear in their names without prior written
33  *    permission of the OpenSSL Project.
34  *
35  * 6. Redistributions of any form whatsoever must retain the following
36  *    acknowledgment:
37  *    "This product includes software developed by the OpenSSL Project
38  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
39  *
40  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
41  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
44  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51  * OF THE POSSIBILITY OF SUCH DAMAGE.
52  * ====================================================================
53  *
54  * This product includes cryptographic software written by Eric Young
55  * (eay@cryptsoft.com).  This product includes software written by Tim
56  * Hudson (tjh@cryptsoft.com).
57  *
58  */
59 
60 #include <limits.h>
61 #include <string.h>
62 
63 #include <openssl/ct.h>
64 #include <openssl/err.h>
65 #include <openssl/evp.h>
66 
67 #include "bytestring.h"
68 #include "ct_local.h"
69 
70 /*
71  * Decodes the base64 string |in| into |out|.
72  * A new string will be malloc'd and assigned to |out|. This will be owned by
73  * the caller. Do not provide a pre-allocated string in |out|.
74  */
75 static int
76 ct_base64_decode(const char *in, unsigned char **out)
77 {
78 	size_t inlen = strlen(in);
79 	int outlen, i;
80 	unsigned char *outbuf = NULL;
81 
82 	if (inlen == 0) {
83 		*out = NULL;
84 		return 0;
85 	}
86 
87 	outlen = (inlen / 4) * 3;
88 	outbuf = malloc(outlen);
89 	if (outbuf == NULL) {
90 		CTerror(ERR_R_MALLOC_FAILURE);
91 		goto err;
92 	}
93 
94 	outlen = EVP_DecodeBlock(outbuf, (unsigned char *)in, inlen);
95 	if (outlen < 0) {
96 		CTerror(CT_R_BASE64_DECODE_ERROR);
97 		goto err;
98 	}
99 
100 	/*
101 	 * Subtract padding bytes from |outlen|.
102 	 * Any more than 2 is malformed.
103 	 */
104 	i = 0;
105 	while (in[--inlen] == '=') {
106 		--outlen;
107 		if (++i > 2)
108 			goto err;
109 	}
110 
111 	*out = outbuf;
112 	return outlen;
113  err:
114 	free(outbuf);
115 	return -1;
116 }
117 
118 SCT *
119 SCT_new_from_base64(unsigned char version, const char *logid_base64,
120     ct_log_entry_type_t entry_type, uint64_t timestamp,
121     const char *extensions_base64, const char *signature_base64)
122 {
123 	unsigned char *dec = NULL;
124 	int declen;
125 	SCT *sct;
126 	CBS cbs;
127 
128 	if ((sct = SCT_new()) == NULL) {
129 		CTerror(ERR_R_MALLOC_FAILURE);
130 		return NULL;
131 	}
132 
133 	/*
134 	 * RFC6962 section 4.1 says we "MUST NOT expect this to be 0", but we
135 	 * can only construct SCT versions that have been defined.
136 	 */
137 	if (!SCT_set_version(sct, version)) {
138 		CTerror(CT_R_SCT_UNSUPPORTED_VERSION);
139 		goto err;
140 	}
141 
142 	declen = ct_base64_decode(logid_base64, &dec);
143 	if (declen < 0) {
144 		CTerror(X509_R_BASE64_DECODE_ERROR);
145 		goto err;
146 	}
147 	if (!SCT_set0_log_id(sct, dec, declen))
148 		goto err;
149 	dec = NULL;
150 
151 	declen = ct_base64_decode(extensions_base64, &dec);
152 	if (declen < 0) {
153 		CTerror(X509_R_BASE64_DECODE_ERROR);
154 		goto err;
155 	}
156 	SCT_set0_extensions(sct, dec, declen);
157 	dec = NULL;
158 
159 	declen = ct_base64_decode(signature_base64, &dec);
160 	if (declen < 0) {
161 		CTerror(X509_R_BASE64_DECODE_ERROR);
162 		goto err;
163 	}
164 
165 	CBS_init(&cbs, dec, declen);
166 	if (!o2i_SCT_signature(sct, &cbs))
167 		goto err;
168 	free(dec);
169 	dec = NULL;
170 
171 	SCT_set_timestamp(sct, timestamp);
172 
173 	if (!SCT_set_log_entry_type(sct, entry_type))
174 		goto err;
175 
176 	return sct;
177 
178  err:
179 	free(dec);
180 	SCT_free(sct);
181 	return NULL;
182 }
183 
184 /*
185  * Allocate, build and returns a new |ct_log| from input |pkey_base64|
186  * It returns 1 on success,
187  * 0 on decoding failure, or invalid parameter if any
188  * -1 on internal (malloc) failure
189  */
190 int
191 CTLOG_new_from_base64(CTLOG **ct_log, const char *pkey_base64, const char *name)
192 {
193 	unsigned char *pkey_der = NULL;
194 	int pkey_der_len;
195 	const unsigned char *p;
196 	EVP_PKEY *pkey = NULL;
197 
198 	if (ct_log == NULL) {
199 	        CTerror(ERR_R_PASSED_NULL_PARAMETER);
200 		return 0;
201 	}
202 
203 	pkey_der_len = ct_base64_decode(pkey_base64, &pkey_der);
204 	if (pkey_der_len < 0) {
205 		CTerror(CT_R_LOG_CONF_INVALID_KEY);
206 		return 0;
207 	}
208 
209 	p = pkey_der;
210 	pkey = d2i_PUBKEY(NULL, &p, pkey_der_len);
211 	free(pkey_der);
212 	if (pkey == NULL) {
213 		CTerror(CT_R_LOG_CONF_INVALID_KEY);
214 		return 0;
215 	}
216 
217 	*ct_log = CTLOG_new(pkey, name);
218 	if (*ct_log == NULL) {
219 		EVP_PKEY_free(pkey);
220 		return 0;
221 	}
222 
223 	return 1;
224 }
225