ct_b64.c revision 1.4
1/*	$OpenBSD: ct_b64.c,v 1.4 2021/12/05 09:37:46 tb Exp $ */
2/*
3 * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
4 *
5 * Licensed under the OpenSSL license (the "License").  You may not use
6 * this file except in compliance with the License.  You can obtain a copy
7 * in the file LICENSE in the source distribution or at
8 * https://www.openssl.org/source/license.html
9 */
10
11#include <limits.h>
12#include <string.h>
13
14#include <openssl/ct.h>
15#include <openssl/err.h>
16#include <openssl/evp.h>
17
18#include "ct_local.h"
19
20/*
21 * Decodes the base64 string |in| into |out|.
22 * A new string will be malloc'd and assigned to |out|. This will be owned by
23 * the caller. Do not provide a pre-allocated string in |out|.
24 */
25static int
26ct_base64_decode(const char *in, unsigned char **out)
27{
28	size_t inlen = strlen(in);
29	int outlen, i;
30	unsigned char *outbuf = NULL;
31
32	if (inlen == 0) {
33		*out = NULL;
34		return 0;
35	}
36
37	outlen = (inlen / 4) * 3;
38	outbuf = malloc(outlen);
39	if (outbuf == NULL) {
40		CTerror(ERR_R_MALLOC_FAILURE);
41		goto err;
42	}
43
44	outlen = EVP_DecodeBlock(outbuf, (unsigned char *)in, inlen);
45	if (outlen < 0) {
46		CTerror(CT_R_BASE64_DECODE_ERROR);
47		goto err;
48	}
49
50	/*
51	 * Subtract padding bytes from |outlen|.
52	 * Any more than 2 is malformed.
53	 */
54	i = 0;
55	while (in[--inlen] == '=') {
56		--outlen;
57		if (++i > 2)
58			goto err;
59	}
60
61	*out = outbuf;
62	return outlen;
63 err:
64	free(outbuf);
65	return -1;
66}
67
68SCT *
69SCT_new_from_base64(unsigned char version, const char *logid_base64,
70    ct_log_entry_type_t entry_type, uint64_t timestamp,
71    const char *extensions_base64, const char *signature_base64)
72{
73	SCT *sct = SCT_new();
74	unsigned char *dec = NULL;
75	const unsigned char* p = NULL;
76	int declen;
77
78	if (sct == NULL) {
79		CTerror(ERR_R_MALLOC_FAILURE);
80		return NULL;
81	}
82
83	/*
84	 * RFC6962 section 4.1 says we "MUST NOT expect this to be 0", but we
85	 * can only construct SCT versions that have been defined.
86	 */
87	if (!SCT_set_version(sct, version)) {
88		CTerror(CT_R_SCT_UNSUPPORTED_VERSION);
89		goto err;
90	}
91
92	declen = ct_base64_decode(logid_base64, &dec);
93	if (declen < 0) {
94		CTerror(X509_R_BASE64_DECODE_ERROR);
95		goto err;
96	}
97	if (!SCT_set0_log_id(sct, dec, declen))
98		goto err;
99	dec = NULL;
100
101	declen = ct_base64_decode(extensions_base64, &dec);
102	if (declen < 0) {
103		CTerror(X509_R_BASE64_DECODE_ERROR);
104		goto err;
105	}
106	SCT_set0_extensions(sct, dec, declen);
107	dec = NULL;
108
109	declen = ct_base64_decode(signature_base64, &dec);
110	if (declen < 0) {
111		CTerror(X509_R_BASE64_DECODE_ERROR);
112		goto err;
113	}
114
115	p = dec;
116	if (o2i_SCT_signature(sct, &p, declen) <= 0)
117		goto err;
118	free(dec);
119	dec = NULL;
120
121	SCT_set_timestamp(sct, timestamp);
122
123	if (!SCT_set_log_entry_type(sct, entry_type))
124		goto err;
125
126	return sct;
127
128 err:
129	free(dec);
130	SCT_free(sct);
131	return NULL;
132}
133
134/*
135 * Allocate, build and returns a new |ct_log| from input |pkey_base64|
136 * It returns 1 on success,
137 * 0 on decoding failure, or invalid parameter if any
138 * -1 on internal (malloc) failure
139 */
140int
141CTLOG_new_from_base64(CTLOG **ct_log, const char *pkey_base64, const char *name)
142{
143	unsigned char *pkey_der = NULL;
144	int pkey_der_len;
145	const unsigned char *p;
146	EVP_PKEY *pkey = NULL;
147
148	if (ct_log == NULL) {
149	        CTerror(ERR_R_PASSED_NULL_PARAMETER);
150		return 0;
151	}
152
153	pkey_der_len = ct_base64_decode(pkey_base64, &pkey_der);
154	if (pkey_der_len < 0) {
155		CTerror(CT_R_LOG_CONF_INVALID_KEY);
156		return 0;
157	}
158
159	p = pkey_der;
160	pkey = d2i_PUBKEY(NULL, &p, pkey_der_len);
161	free(pkey_der);
162	if (pkey == NULL) {
163		CTerror(CT_R_LOG_CONF_INVALID_KEY);
164		return 0;
165	}
166
167	*ct_log = CTLOG_new(pkey, name);
168	if (*ct_log == NULL) {
169		EVP_PKEY_free(pkey);
170		return 0;
171	}
172
173	return 1;
174}
175