1/* Copyright 2014 The BoringSSL Authors 2 * 3 * Permission to use, copy, modify, and/or distribute this software for any 4 * purpose with or without fee is hereby granted, provided that the above 5 * copyright notice and this permission notice appear in all copies. 6 * 7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ 14 15#include <openssl/aead.h> 16 17#include <assert.h> 18#include <string.h> 19 20#include <openssl/cipher.h> 21#include <openssl/err.h> 22#include <openssl/mem.h> 23 24#include "../../internal.h" 25#include "internal.h" 26 27 28size_t EVP_AEAD_key_length(const EVP_AEAD *aead) { return aead->key_len; } 29 30size_t EVP_AEAD_nonce_length(const EVP_AEAD *aead) { return aead->nonce_len; } 31 32size_t EVP_AEAD_max_overhead(const EVP_AEAD *aead) { return aead->overhead; } 33 34size_t EVP_AEAD_max_tag_len(const EVP_AEAD *aead) { return aead->max_tag_len; } 35 36void EVP_AEAD_CTX_zero(EVP_AEAD_CTX *ctx) { 37 OPENSSL_memset(ctx, 0, sizeof(EVP_AEAD_CTX)); 38} 39 40EVP_AEAD_CTX *EVP_AEAD_CTX_new(const EVP_AEAD *aead, const uint8_t *key, 41 size_t key_len, size_t tag_len) { 42 EVP_AEAD_CTX *ctx = 43 reinterpret_cast<EVP_AEAD_CTX *>(OPENSSL_malloc(sizeof(EVP_AEAD_CTX))); 44 if (!ctx) { 45 return NULL; 46 } 47 EVP_AEAD_CTX_zero(ctx); 48 49 if (EVP_AEAD_CTX_init(ctx, aead, key, key_len, tag_len, NULL)) { 50 return ctx; 51 } 52 53 EVP_AEAD_CTX_free(ctx); 54 return NULL; 55} 56 57void EVP_AEAD_CTX_free(EVP_AEAD_CTX *ctx) { 58 if (ctx == NULL) { 59 return; 60 } 61 EVP_AEAD_CTX_cleanup(ctx); 62 OPENSSL_free(ctx); 63} 64 65int EVP_AEAD_CTX_init(EVP_AEAD_CTX *ctx, const EVP_AEAD *aead, 66 const uint8_t *key, size_t key_len, size_t tag_len, 67 ENGINE *impl) { 68 if (!aead->init) { 69 OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_NO_DIRECTION_SET); 70 ctx->aead = NULL; 71 return 0; 72 } 73 return EVP_AEAD_CTX_init_with_direction(ctx, aead, key, key_len, tag_len, 74 evp_aead_open); 75} 76 77int EVP_AEAD_CTX_init_with_direction(EVP_AEAD_CTX *ctx, const EVP_AEAD *aead, 78 const uint8_t *key, size_t key_len, 79 size_t tag_len, 80 enum evp_aead_direction_t dir) { 81 if (key_len != aead->key_len) { 82 OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_KEY_SIZE); 83 ctx->aead = NULL; 84 return 0; 85 } 86 87 ctx->aead = aead; 88 89 int ok; 90 if (aead->init) { 91 ok = aead->init(ctx, key, key_len, tag_len); 92 } else { 93 ok = aead->init_with_direction(ctx, key, key_len, tag_len, dir); 94 } 95 96 if (!ok) { 97 ctx->aead = NULL; 98 } 99 100 return ok; 101} 102 103void EVP_AEAD_CTX_cleanup(EVP_AEAD_CTX *ctx) { 104 if (ctx->aead == NULL) { 105 return; 106 } 107 ctx->aead->cleanup(ctx); 108 ctx->aead = NULL; 109} 110 111// check_alias returns 1 if |out| is compatible with |in| and 0 otherwise. If 112// |in| and |out| alias, we require that |in| == |out|. 113static int check_alias(const uint8_t *in, size_t in_len, const uint8_t *out, 114 size_t out_len) { 115 if (!buffers_alias(in, in_len, out, out_len)) { 116 return 1; 117 } 118 119 return in == out; 120} 121 122int EVP_AEAD_CTX_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len, 123 size_t max_out_len, const uint8_t *nonce, 124 size_t nonce_len, const uint8_t *in, size_t in_len, 125 const uint8_t *ad, size_t ad_len) { 126 if (in_len + ctx->aead->overhead < in_len /* overflow */) { 127 OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); 128 goto error; 129 } 130 131 if (max_out_len < in_len) { 132 OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); 133 goto error; 134 } 135 136 if (!check_alias(in, in_len, out, max_out_len)) { 137 OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_OUTPUT_ALIASES_INPUT); 138 goto error; 139 } 140 141 size_t out_tag_len; 142 if (ctx->aead->seal_scatter(ctx, out, out + in_len, &out_tag_len, 143 max_out_len - in_len, nonce, nonce_len, in, 144 in_len, NULL, 0, ad, ad_len)) { 145 *out_len = in_len + out_tag_len; 146 return 1; 147 } 148 149error: 150 // In the event of an error, clear the output buffer so that a caller 151 // that doesn't check the return value doesn't send raw data. 152 OPENSSL_memset(out, 0, max_out_len); 153 *out_len = 0; 154 return 0; 155} 156 157int EVP_AEAD_CTX_seal_scatter(const EVP_AEAD_CTX *ctx, uint8_t *out, 158 uint8_t *out_tag, size_t *out_tag_len, 159 size_t max_out_tag_len, const uint8_t *nonce, 160 size_t nonce_len, const uint8_t *in, 161 size_t in_len, const uint8_t *extra_in, 162 size_t extra_in_len, const uint8_t *ad, 163 size_t ad_len) { 164 // |in| and |out| may alias exactly, |out_tag| may not alias. 165 if (!check_alias(in, in_len, out, in_len) || 166 buffers_alias(out, in_len, out_tag, max_out_tag_len) || 167 buffers_alias(in, in_len, out_tag, max_out_tag_len)) { 168 OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_OUTPUT_ALIASES_INPUT); 169 goto error; 170 } 171 172 if (!ctx->aead->seal_scatter_supports_extra_in && extra_in_len) { 173 OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_OPERATION); 174 goto error; 175 } 176 177 if (ctx->aead->seal_scatter(ctx, out, out_tag, out_tag_len, max_out_tag_len, 178 nonce, nonce_len, in, in_len, extra_in, 179 extra_in_len, ad, ad_len)) { 180 return 1; 181 } 182 183error: 184 // In the event of an error, clear the output buffer so that a caller 185 // that doesn't check the return value doesn't send raw data. 186 OPENSSL_memset(out, 0, in_len); 187 OPENSSL_memset(out_tag, 0, max_out_tag_len); 188 *out_tag_len = 0; 189 return 0; 190} 191 192int EVP_AEAD_CTX_open(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len, 193 size_t max_out_len, const uint8_t *nonce, 194 size_t nonce_len, const uint8_t *in, size_t in_len, 195 const uint8_t *ad, size_t ad_len) { 196 size_t plaintext_len; 197 if (!check_alias(in, in_len, out, max_out_len)) { 198 OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_OUTPUT_ALIASES_INPUT); 199 goto error; 200 } 201 202 if (ctx->aead->open) { 203 if (!ctx->aead->open(ctx, out, out_len, max_out_len, nonce, nonce_len, in, 204 in_len, ad, ad_len)) { 205 goto error; 206 } 207 return 1; 208 } 209 210 // AEADs that use the default implementation of open() must set |tag_len| at 211 // initialization time. 212 assert(ctx->tag_len); 213 214 if (in_len < ctx->tag_len) { 215 OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); 216 goto error; 217 } 218 219 plaintext_len = in_len - ctx->tag_len; 220 if (max_out_len < plaintext_len) { 221 OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); 222 goto error; 223 } 224 if (EVP_AEAD_CTX_open_gather(ctx, out, nonce, nonce_len, in, plaintext_len, 225 in + plaintext_len, ctx->tag_len, ad, ad_len)) { 226 *out_len = plaintext_len; 227 return 1; 228 } 229 230error: 231 // In the event of an error, clear the output buffer so that a caller 232 // that doesn't check the return value doesn't try and process bad 233 // data. 234 OPENSSL_memset(out, 0, max_out_len); 235 *out_len = 0; 236 return 0; 237} 238 239int EVP_AEAD_CTX_open_gather(const EVP_AEAD_CTX *ctx, uint8_t *out, 240 const uint8_t *nonce, size_t nonce_len, 241 const uint8_t *in, size_t in_len, 242 const uint8_t *in_tag, size_t in_tag_len, 243 const uint8_t *ad, size_t ad_len) { 244 if (!check_alias(in, in_len, out, in_len)) { 245 OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_OUTPUT_ALIASES_INPUT); 246 goto error; 247 } 248 249 if (!ctx->aead->open_gather) { 250 OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_CTRL_NOT_IMPLEMENTED); 251 goto error; 252 } 253 254 if (ctx->aead->open_gather(ctx, out, nonce, nonce_len, in, in_len, in_tag, 255 in_tag_len, ad, ad_len)) { 256 return 1; 257 } 258 259error: 260 // In the event of an error, clear the output buffer so that a caller 261 // that doesn't check the return value doesn't try and process bad 262 // data. 263 OPENSSL_memset(out, 0, in_len); 264 return 0; 265} 266 267const EVP_AEAD *EVP_AEAD_CTX_aead(const EVP_AEAD_CTX *ctx) { return ctx->aead; } 268 269int EVP_AEAD_CTX_get_iv(const EVP_AEAD_CTX *ctx, const uint8_t **out_iv, 270 size_t *out_len) { 271 if (ctx->aead->get_iv == NULL) { 272 OPENSSL_PUT_ERROR(CIPHER, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); 273 return 0; 274 } 275 276 return ctx->aead->get_iv(ctx, out_iv, out_len); 277} 278 279int EVP_AEAD_CTX_tag_len(const EVP_AEAD_CTX *ctx, size_t *out_tag_len, 280 const size_t in_len, const size_t extra_in_len) { 281 assert(ctx->aead->seal_scatter_supports_extra_in || !extra_in_len); 282 283 if (ctx->aead->tag_len) { 284 *out_tag_len = ctx->aead->tag_len(ctx, in_len, extra_in_len); 285 return 1; 286 } 287 288 if (extra_in_len + ctx->tag_len < extra_in_len) { 289 OPENSSL_PUT_ERROR(CIPHER, ERR_R_OVERFLOW); 290 *out_tag_len = 0; 291 return 0; 292 } 293 *out_tag_len = extra_in_len + ctx->tag_len; 294 return 1; 295} 296