1/* 2 * Copyright 2007-2018 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 <stdio.h> 11#include "internal/cryptlib.h" 12#include <openssl/x509.h> 13#include <openssl/x509v3.h> 14#include <openssl/evp.h> 15#include <openssl/err.h> 16#include "crypto/siphash.h" 17#include "siphash_local.h" 18#include "crypto/evp.h" 19 20/* SIPHASH pkey context structure */ 21 22typedef struct siphash_pkey_ctx_st { 23 ASN1_OCTET_STRING ktmp; /* Temp storage for key */ 24 SIPHASH ctx; 25} SIPHASH_PKEY_CTX; 26 27static int pkey_siphash_init(EVP_PKEY_CTX *ctx) 28{ 29 SIPHASH_PKEY_CTX *pctx; 30 31 if ((pctx = OPENSSL_zalloc(sizeof(*pctx))) == NULL) { 32 CRYPTOerr(CRYPTO_F_PKEY_SIPHASH_INIT, ERR_R_MALLOC_FAILURE); 33 return 0; 34 } 35 pctx->ktmp.type = V_ASN1_OCTET_STRING; 36 37 EVP_PKEY_CTX_set_data(ctx, pctx); 38 EVP_PKEY_CTX_set0_keygen_info(ctx, NULL, 0); 39 return 1; 40} 41 42static void pkey_siphash_cleanup(EVP_PKEY_CTX *ctx) 43{ 44 SIPHASH_PKEY_CTX *pctx = EVP_PKEY_CTX_get_data(ctx); 45 46 if (pctx != NULL) { 47 OPENSSL_clear_free(pctx->ktmp.data, pctx->ktmp.length); 48 OPENSSL_clear_free(pctx, sizeof(*pctx)); 49 EVP_PKEY_CTX_set_data(ctx, NULL); 50 } 51} 52 53static int pkey_siphash_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) 54{ 55 SIPHASH_PKEY_CTX *sctx, *dctx; 56 57 /* allocate memory for dst->data and a new SIPHASH_CTX in dst->data->ctx */ 58 if (!pkey_siphash_init(dst)) 59 return 0; 60 sctx = EVP_PKEY_CTX_get_data(src); 61 dctx = EVP_PKEY_CTX_get_data(dst); 62 if (ASN1_STRING_get0_data(&sctx->ktmp) != NULL && 63 !ASN1_STRING_copy(&dctx->ktmp, &sctx->ktmp)) { 64 /* cleanup and free the SIPHASH_PKEY_CTX in dst->data */ 65 pkey_siphash_cleanup(dst); 66 return 0; 67 } 68 memcpy(&dctx->ctx, &sctx->ctx, sizeof(SIPHASH)); 69 return 1; 70} 71 72static int pkey_siphash_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) 73{ 74 ASN1_OCTET_STRING *key; 75 SIPHASH_PKEY_CTX *pctx = EVP_PKEY_CTX_get_data(ctx); 76 77 if (ASN1_STRING_get0_data(&pctx->ktmp) == NULL) 78 return 0; 79 key = ASN1_OCTET_STRING_dup(&pctx->ktmp); 80 if (key == NULL) 81 return 0; 82 return EVP_PKEY_assign_SIPHASH(pkey, key); 83} 84 85static int int_update(EVP_MD_CTX *ctx, const void *data, size_t count) 86{ 87 SIPHASH_PKEY_CTX *pctx = EVP_PKEY_CTX_get_data(EVP_MD_CTX_pkey_ctx(ctx)); 88 89 SipHash_Update(&pctx->ctx, data, count); 90 return 1; 91} 92 93static int siphash_signctx_init(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx) 94{ 95 SIPHASH_PKEY_CTX *pctx = EVP_PKEY_CTX_get_data(ctx); 96 const unsigned char* key; 97 size_t len; 98 99 key = EVP_PKEY_get0_siphash(EVP_PKEY_CTX_get0_pkey(ctx), &len); 100 if (key == NULL || len != SIPHASH_KEY_SIZE) 101 return 0; 102 EVP_MD_CTX_set_flags(mctx, EVP_MD_CTX_FLAG_NO_INIT); 103 EVP_MD_CTX_set_update_fn(mctx, int_update); 104 return SipHash_Init(&pctx->ctx, key, 0, 0); 105} 106static int siphash_signctx(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen, 107 EVP_MD_CTX *mctx) 108{ 109 SIPHASH_PKEY_CTX *pctx = ctx->data; 110 111 *siglen = SipHash_hash_size(&pctx->ctx); 112 if (sig != NULL) 113 return SipHash_Final(&pctx->ctx, sig, *siglen); 114 return 1; 115} 116 117static int pkey_siphash_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) 118{ 119 SIPHASH_PKEY_CTX *pctx = EVP_PKEY_CTX_get_data(ctx); 120 const unsigned char *key; 121 size_t len; 122 123 switch (type) { 124 125 case EVP_PKEY_CTRL_MD: 126 /* ignore */ 127 break; 128 129 case EVP_PKEY_CTRL_SET_DIGEST_SIZE: 130 return SipHash_set_hash_size(&pctx->ctx, p1); 131 132 case EVP_PKEY_CTRL_SET_MAC_KEY: 133 case EVP_PKEY_CTRL_DIGESTINIT: 134 if (type == EVP_PKEY_CTRL_SET_MAC_KEY) { 135 /* user explicitly setting the key */ 136 key = p2; 137 len = p1; 138 } else { 139 /* user indirectly setting the key via EVP_DigestSignInit */ 140 key = EVP_PKEY_get0_siphash(EVP_PKEY_CTX_get0_pkey(ctx), &len); 141 } 142 if (key == NULL || len != SIPHASH_KEY_SIZE || 143 !ASN1_OCTET_STRING_set(&pctx->ktmp, key, len)) 144 return 0; 145 /* use default rounds (2,4) */ 146 return SipHash_Init(&pctx->ctx, ASN1_STRING_get0_data(&pctx->ktmp), 147 0, 0); 148 149 default: 150 return -2; 151 152 } 153 return 1; 154} 155 156static int pkey_siphash_ctrl_str(EVP_PKEY_CTX *ctx, 157 const char *type, const char *value) 158{ 159 if (value == NULL) 160 return 0; 161 if (strcmp(type, "digestsize") == 0) { 162 size_t hash_size = atoi(value); 163 164 return pkey_siphash_ctrl(ctx, EVP_PKEY_CTRL_SET_DIGEST_SIZE, hash_size, 165 NULL); 166 } 167 if (strcmp(type, "key") == 0) 168 return EVP_PKEY_CTX_str2ctrl(ctx, EVP_PKEY_CTRL_SET_MAC_KEY, value); 169 if (strcmp(type, "hexkey") == 0) 170 return EVP_PKEY_CTX_hex2ctrl(ctx, EVP_PKEY_CTRL_SET_MAC_KEY, value); 171 return -2; 172} 173 174const EVP_PKEY_METHOD siphash_pkey_meth = { 175 EVP_PKEY_SIPHASH, 176 EVP_PKEY_FLAG_SIGCTX_CUSTOM, /* we don't deal with a separate MD */ 177 pkey_siphash_init, 178 pkey_siphash_copy, 179 pkey_siphash_cleanup, 180 181 0, 0, 182 183 0, 184 pkey_siphash_keygen, 185 186 0, 0, 187 188 0, 0, 189 190 0, 0, 191 192 siphash_signctx_init, 193 siphash_signctx, 194 195 0, 0, 196 197 0, 0, 198 199 0, 0, 200 201 0, 0, 202 203 pkey_siphash_ctrl, 204 pkey_siphash_ctrl_str 205}; 206