xref: /openbsd/lib/libcrypto/ct/ct_b64.c (revision 5a38ef86)
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  */
25 static int
26 ct_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 
68 SCT *
69 SCT_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  */
140 int
141 CTLOG_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