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