selfencrypt.c (9284B)
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is PRIVATE to SSL. 4 * 5 * This Source Code Form is subject to the terms of the Mozilla Public 6 * License, v. 2.0. If a copy of the MPL was not distributed with this 7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 8 9 #include "nss.h" 10 #include "blapit.h" 11 #include "pk11func.h" 12 #include "ssl.h" 13 #include "sslt.h" 14 #include "sslimpl.h" 15 #include "selfencrypt.h" 16 17 static SECStatus 18 ssl_MacBuffer(PK11SymKey *key, CK_MECHANISM_TYPE mech, 19 const unsigned char *in, unsigned int len, 20 unsigned char *mac, unsigned int *macLen, unsigned int maxMacLen) 21 { 22 PK11Context *ctx; 23 SECItem macParam = { 0, NULL, 0 }; 24 unsigned int computedLen; 25 SECStatus rv; 26 27 ctx = PK11_CreateContextBySymKey(mech, CKA_SIGN, key, &macParam); 28 if (!ctx) { 29 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 30 return SECFailure; 31 } 32 33 rv = PK11_DigestBegin(ctx); 34 if (rv != SECSuccess) { 35 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 36 goto loser; 37 } 38 39 rv = PK11_DigestOp(ctx, in, len); 40 if (rv != SECSuccess) { 41 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 42 goto loser; 43 } 44 45 rv = PK11_DigestFinal(ctx, mac, &computedLen, maxMacLen); 46 if (rv != SECSuccess) { 47 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 48 goto loser; 49 } 50 51 *macLen = maxMacLen; 52 PK11_DestroyContext(ctx, PR_TRUE); 53 return SECSuccess; 54 55 loser: 56 PK11_DestroyContext(ctx, PR_TRUE); 57 return SECFailure; 58 } 59 60 #ifdef UNSAFE_FUZZER_MODE 61 SECStatus 62 ssl_SelfEncryptProtectInt( 63 PK11SymKey *encKey, PK11SymKey *macKey, 64 const unsigned char *keyName, 65 const PRUint8 *in, unsigned int inLen, 66 PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen) 67 { 68 if (inLen > maxOutLen) { 69 PORT_SetError(SEC_ERROR_INVALID_ARGS); 70 return SECFailure; 71 } 72 73 PORT_Memcpy(out, in, inLen); 74 *outLen = inLen; 75 76 return 0; 77 } 78 79 SECStatus 80 ssl_SelfEncryptUnprotectInt( 81 PK11SymKey *encKey, PK11SymKey *macKey, const unsigned char *keyName, 82 const PRUint8 *in, unsigned int inLen, 83 PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen) 84 { 85 if (inLen > maxOutLen) { 86 PORT_SetError(SEC_ERROR_INVALID_ARGS); 87 return SECFailure; 88 } 89 90 PORT_Memcpy(out, in, inLen); 91 *outLen = inLen; 92 93 return 0; 94 } 95 96 #else 97 /* 98 * Structure is. 99 * 100 * struct { 101 * opaque keyName[16]; 102 * opaque iv[16]; 103 * opaque ciphertext<16..2^16-1>; 104 * opaque mac[32]; 105 * } SelfEncrypted; 106 * 107 * We are using AES-CBC + HMAC-SHA256 in Encrypt-then-MAC mode for 108 * two reasons: 109 * 110 * 1. It's what we already used for tickets. 111 * 2. We don't have to worry about nonce collisions as much 112 * (the chance is lower because we have a random 128-bit nonce 113 * and they are less serious than with AES-GCM). 114 */ 115 SECStatus 116 ssl_SelfEncryptProtectInt( 117 PK11SymKey *encKey, PK11SymKey *macKey, 118 const unsigned char *keyName, 119 const PRUint8 *in, unsigned int inLen, 120 PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen) 121 { 122 unsigned int len; 123 unsigned int lenOffset; 124 unsigned char iv[AES_BLOCK_SIZE]; 125 SECItem ivItem = { siBuffer, iv, sizeof(iv) }; 126 /* Write directly to out. */ 127 sslBuffer buf = SSL_BUFFER_FIXED(out, maxOutLen); 128 SECStatus rv; 129 130 /* Generate a random IV */ 131 rv = PK11_GenerateRandom(iv, sizeof(iv)); 132 if (rv != SECSuccess) { 133 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 134 return SECFailure; 135 } 136 137 /* Add header. */ 138 rv = sslBuffer_Append(&buf, keyName, SELF_ENCRYPT_KEY_NAME_LEN); 139 if (rv != SECSuccess) { 140 return SECFailure; 141 } 142 rv = sslBuffer_Append(&buf, iv, sizeof(iv)); 143 if (rv != SECSuccess) { 144 return SECFailure; 145 } 146 147 /* Leave space for the length of the ciphertext. */ 148 rv = sslBuffer_Skip(&buf, 2, &lenOffset); 149 if (rv != SECSuccess) { 150 return SECFailure; 151 } 152 153 /* Encode the ciphertext in place. */ 154 rv = PK11_Encrypt(encKey, CKM_AES_CBC_PAD, &ivItem, 155 SSL_BUFFER_NEXT(&buf), &len, 156 SSL_BUFFER_SPACE(&buf), in, inLen); 157 if (rv != SECSuccess) { 158 return SECFailure; 159 } 160 rv = sslBuffer_Skip(&buf, len, NULL); 161 if (rv != SECSuccess) { 162 return SECFailure; 163 } 164 165 rv = sslBuffer_InsertLength(&buf, lenOffset, 2); 166 if (rv != SECSuccess) { 167 return SECFailure; 168 } 169 170 /* MAC the entire output buffer into the output. */ 171 PORT_Assert(buf.space - buf.len >= SHA256_LENGTH); 172 rv = ssl_MacBuffer(macKey, CKM_SHA256_HMAC, 173 SSL_BUFFER_BASE(&buf), /* input */ 174 SSL_BUFFER_LEN(&buf), 175 SSL_BUFFER_NEXT(&buf), &len, /* output */ 176 SHA256_LENGTH); 177 if (rv != SECSuccess) { 178 return SECFailure; 179 } 180 rv = sslBuffer_Skip(&buf, len, NULL); 181 if (rv != SECSuccess) { 182 return SECFailure; 183 } 184 185 *outLen = SSL_BUFFER_LEN(&buf); 186 return SECSuccess; 187 } 188 189 SECStatus 190 ssl_SelfEncryptUnprotectInt( 191 PK11SymKey *encKey, PK11SymKey *macKey, const unsigned char *keyName, 192 const PRUint8 *in, unsigned int inLen, 193 PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen) 194 { 195 sslReader reader = SSL_READER(in, inLen); 196 197 sslReadBuffer encodedKeyNameBuffer = { 0 }; 198 SECStatus rv = sslRead_Read(&reader, SELF_ENCRYPT_KEY_NAME_LEN, 199 &encodedKeyNameBuffer); 200 if (rv != SECSuccess) { 201 return SECFailure; 202 } 203 204 sslReadBuffer ivBuffer = { 0 }; 205 rv = sslRead_Read(&reader, AES_BLOCK_SIZE, &ivBuffer); 206 if (rv != SECSuccess) { 207 return SECFailure; 208 } 209 210 PRUint64 cipherTextLen = 0; 211 rv = sslRead_ReadNumber(&reader, 2, &cipherTextLen); 212 if (rv != SECSuccess) { 213 return SECFailure; 214 } 215 216 sslReadBuffer cipherTextBuffer = { 0 }; 217 rv = sslRead_Read(&reader, (unsigned int)cipherTextLen, &cipherTextBuffer); 218 if (rv != SECSuccess) { 219 return SECFailure; 220 } 221 unsigned int bytesToMac = reader.offset; 222 223 sslReadBuffer encodedMacBuffer = { 0 }; 224 rv = sslRead_Read(&reader, SHA256_LENGTH, &encodedMacBuffer); 225 if (rv != SECSuccess) { 226 return SECFailure; 227 } 228 229 /* Make sure we're at the end of the block. */ 230 if (reader.offset != reader.buf.len) { 231 PORT_SetError(SEC_ERROR_BAD_DATA); 232 return SECFailure; 233 } 234 235 /* Now that everything is decoded, we can make progress. */ 236 /* 1. Check that we have the right key. */ 237 if (PORT_Memcmp(keyName, encodedKeyNameBuffer.buf, SELF_ENCRYPT_KEY_NAME_LEN)) { 238 PORT_SetError(SEC_ERROR_NOT_A_RECIPIENT); 239 return SECFailure; 240 } 241 242 /* 2. Check the MAC */ 243 unsigned char computedMac[SHA256_LENGTH]; 244 unsigned int computedMacLen = 0; 245 rv = ssl_MacBuffer(macKey, CKM_SHA256_HMAC, in, bytesToMac, 246 computedMac, &computedMacLen, sizeof(computedMac)); 247 if (rv != SECSuccess) { 248 return SECFailure; 249 } 250 PORT_Assert(computedMacLen == SHA256_LENGTH); 251 if (NSS_SecureMemcmp(computedMac, encodedMacBuffer.buf, computedMacLen) != 0) { 252 PORT_SetError(SEC_ERROR_BAD_DATA); 253 return SECFailure; 254 } 255 256 /* 3. OK, it verifies, now decrypt. */ 257 SECItem ivItem = { siBuffer, (unsigned char *)ivBuffer.buf, AES_BLOCK_SIZE }; 258 rv = PK11_Decrypt(encKey, CKM_AES_CBC_PAD, &ivItem, 259 out, outLen, maxOutLen, cipherTextBuffer.buf, cipherTextLen); 260 if (rv != SECSuccess) { 261 return SECFailure; 262 } 263 264 return SECSuccess; 265 } 266 #endif 267 268 /* Predict the size of the encrypted data, including padding */ 269 unsigned int 270 ssl_SelfEncryptGetProtectedSize(unsigned int inLen) 271 { 272 return SELF_ENCRYPT_KEY_NAME_LEN + 273 AES_BLOCK_SIZE + 274 2 + 275 ((inLen / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE + /* Padded */ 276 SHA256_LENGTH; 277 } 278 279 SECStatus 280 ssl_SelfEncryptProtect( 281 sslSocket *ss, const PRUint8 *in, unsigned int inLen, 282 PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen) 283 { 284 PRUint8 keyName[SELF_ENCRYPT_KEY_NAME_LEN]; 285 PK11SymKey *encKey; 286 PK11SymKey *macKey; 287 SECStatus rv; 288 289 /* Get session ticket keys. */ 290 rv = ssl_GetSelfEncryptKeys(ss, keyName, &encKey, &macKey); 291 if (rv != SECSuccess) { 292 SSL_DBG(("%d: SSL[%d]: Unable to get/generate self-encrypt keys.", 293 SSL_GETPID(), ss->fd)); 294 return SECFailure; 295 } 296 297 return ssl_SelfEncryptProtectInt(encKey, macKey, keyName, 298 in, inLen, out, outLen, maxOutLen); 299 } 300 301 SECStatus 302 ssl_SelfEncryptUnprotect( 303 sslSocket *ss, const PRUint8 *in, unsigned int inLen, 304 PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen) 305 { 306 PRUint8 keyName[SELF_ENCRYPT_KEY_NAME_LEN]; 307 PK11SymKey *encKey; 308 PK11SymKey *macKey; 309 SECStatus rv; 310 311 /* Get session ticket keys. */ 312 rv = ssl_GetSelfEncryptKeys(ss, keyName, &encKey, &macKey); 313 if (rv != SECSuccess) { 314 SSL_DBG(("%d: SSL[%d]: Unable to get/generate self-encrypt keys.", 315 SSL_GETPID(), ss->fd)); 316 return SECFailure; 317 } 318 319 return ssl_SelfEncryptUnprotectInt(encKey, macKey, keyName, 320 in, inLen, out, outLen, maxOutLen); 321 }