Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(340)

Unified Diff: crypto/nss_util.cc

Issue 7756025: Changed OAuth token+secret encryption to use supplemental user key. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« crypto/nss_util.h ('K') | « crypto/nss_util.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: crypto/nss_util.cc
===================================================================
--- crypto/nss_util.cc (revision 99168)
+++ crypto/nss_util.cc (working copy)
@@ -83,6 +83,148 @@
return dir;
}
+#if defined(OS_CHROMEOS)
+
+static unsigned char kSupplementalUserKeyId[] = {
wtc 2011/09/02 22:31:08 Nit: remove 'static' because this is in the anonym
zel 2011/09/03 01:52:22 On ChromeOS, this key will be used to perform AES
+ 0xCC, 0x13, 0x19, 0xDE, 0x75, 0x5E, 0xFE, 0x00,
+ 0x5E, 0x71, 0xD4, 0xA6, 0x00, 0x00, 0x00, 0xCC
+};
+
+const char kSupplementalKeyNickname[] = "ChromeOS_SupplementalUserKey";
+
+struct SDRResult
+{
wtc 2011/09/02 22:31:08 Nit: put '{' on the previous line. Document what
zel 2011/09/03 01:52:22 I have removed this code addressed in this and com
+ SECItem keyid;
+ SECAlgorithmID alg;
+ SECItem data;
+};
+typedef struct SDRResult SDRResult;
wtc 2011/09/02 22:31:08 Remove this typedef. This is not necessary in C++
zel 2011/09/03 01:52:22 Removed.
+
+SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
+
+static SEC_ASN1Template g_encoding_template[] = {
+ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof (SDRResult) },
+ { SEC_ASN1_OCTET_STRING, offsetof(SDRResult, keyid) },
+ { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(SDRResult, alg),
+ SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
+ { SEC_ASN1_OCTET_STRING, offsetof(SDRResult, data) },
+ { 0 }
+};
+
+// Local utility functions for padding/unpadding an incoming data block
+// to the mechanism block size.
+
+SECStatus PadBlock(SECItem *data, unsigned int blockSize, SECItem *result) {
wtc 2011/09/02 22:31:08 The function arguments and variables in these func
zel 2011/09/03 01:52:22 Removed.
+ SECStatus rv = SECSuccess;
+ unsigned int padLength;
+ unsigned int i;
+
+ result->data = 0;
+ result->len = 0;
+
+ // This algorithm always adds to the block (to indicate the number
+ // of pad bytes). So allocate a block large enough.
+ padLength = blockSize - (data->len % blockSize);
+ result->len = data->len + padLength;
+ result->data = (unsigned char *) PORT_Alloc(result->len);
wtc 2011/09/02 22:31:08 Nit: try to use C++ casts where possible. This is
zel 2011/09/03 01:52:22 Removed.
+
+ // Copy the data
+ PORT_Memcpy(result->data, data->data, data->len);
+
+ // Add the pad values
+ for(i = data->len; i < result->len; i++)
+ result->data[i] = (unsigned char) padLength;
+
+ return rv;
+}
+
+SECStatus UnpadBlock(SECItem *data, unsigned int blockSize, SECItem *result) {
+ SECStatus rv = SECSuccess;
+ unsigned int padLength;
+ unsigned int i;
+
+ result->data = 0;
+ result->len = 0;
+
+ // Remove the padding from the end if the input data.
+ if (data->len == 0 || data->len % blockSize != 0) {
+ rv = SECFailure;
+ goto done;
+ }
+
+ padLength = data->data[data->len-1];
+ if (padLength > blockSize) {
+ rv = SECFailure;
+ goto done;
+ }
+
+ // Verify padding.
+ for (i = data->len - padLength; i < data->len; i++) {
+ if (data->data[i] != padLength) {
+ rv = SECFailure;
+ goto done;
+ }
+ }
+
+ result->len = data->len - padLength;
+ result->data = (unsigned char *) PORT_Alloc(result->len);
+ if (!result->data) {
+ rv = SECFailure;
+ goto done;
+ }
+
+ PORT_Memcpy(result->data, data->data, result->len);
+
+ if (padLength < 2) {
+ return SECWouldBlock;
+ }
+
+done:
+ return rv;
+}
+
+// decrypt a block
+SECStatus pk11Decrypt(PK11SlotInfo *slot, PLArenaPool *arena,
+ CK_MECHANISM_TYPE type, PK11SymKey *key,
+ SECItem *params, SECItem *in, SECItem *result) {
+ PK11Context *ctx = 0;
+ SECItem paddedResult;
+ SECStatus rv;
+
+ paddedResult.len = 0;
+ paddedResult.data = 0;
+
+ ctx = PK11_CreateContextBySymKey(type, CKA_DECRYPT, key, params);
+ if (!ctx) {
+ rv = SECFailure;
+ goto done;
+ }
+
+ paddedResult.len = in->len;
+ paddedResult.data = reinterpret_cast<unsigned char *>(
+ PORT_ArenaAlloc(arena, paddedResult.len));
+
+ rv = PK11_CipherOp(ctx, paddedResult.data,
+ reinterpret_cast<int*>(&paddedResult.len), paddedResult.len,
+ in->data, in->len);
+ if (rv != SECSuccess)
+ goto done;
+
+ PK11_Finalize(ctx);
+
+ // Remove the padding.
+ rv = UnpadBlock(&paddedResult, PK11_GetBlockSize(type, 0), result);
+ if (rv)
+ goto done;
+
+done:
+ if (ctx)
+ PK11_DestroyContext(ctx, PR_TRUE);
+ return rv;
+}
wtc 2011/09/02 22:31:08 If these functions are copied from NSS or Mozilla,
zel 2011/09/03 01:52:22 Removed.
+#endif
+
+
wtc 2011/09/02 22:31:08 Nit: remove one blank line.
// On non-chromeos platforms, return the default config directory.
// On chromeos, return a read-only directory with fake root CA certs for testing
// (which will not exist on non-testing images). These root CA certs are used
@@ -287,7 +429,317 @@
GetTPMTokenInfo(&token_name, NULL);
return FindSlotWithTokenName(token_name);
}
+/*
+ bool GetSupplementalUserKey(std::string* user_key) {
+ OpenPersistentNSSDB();
+ SECStatus rv = SECSuccess;
+ PK11SlotInfo* slot = NULL;
+ PK11SymKey *key = NULL;
+ SECItem* keyData = NULL;
+ SECItem keyID;
+ CK_MECHANISM_TYPE type = CKM_DES3_CBC;
+ PLArenaPool *arena = 0;
+
+ arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
+ if (!arena)
+ goto done;
+
+ slot = GetPublicNSSKeySlot();
+ if (!slot) {
+ rv = SECFailure;
+ goto done;
+ }
+
+ rv = PK11_Authenticate(slot, PR_TRUE, NULL);
+ if (rv != SECSuccess)
+ goto done;
+
+ keyID.type = siBuffer;
+ keyID.data = kSupplementalUserKeyId;
+ keyID.len = static_cast<int>(sizeof(kSupplementalUserKeyId));
+
+ // Find/generate AES key.
+ key = PK11_FindFixedKey(slot, type, &keyID, NULL);
+ if (!key) {
+
+ key = PK11_TokenKeyGen(slot, type, 0, 0, &keyID, PR_TRUE, NULL);
+ if (key) {
+ rv = PK11_SetSymKeyNickname(key, kSupplementalKeyNickname);
+ if (rv != SECSuccess)
+ goto done;
+ } else {
+ int error = PORT_GetError();
+ LOG(WARNING) << "Got error: " << error;
+ }
+ }
+
+ if (!key) {
+ rv = SECFailure;
+ goto done;
+ }
+
+ keyData = PK11_GetKeyData(key);
+ if (!keyData) {
+ rv = SECFailure;
+ goto done;
+ }
+
+ *user_key = std::string(
+ reinterpret_cast<const char*>(keyData->data), keyData->len);
+
+ done:
+ if (arena)
+ PORT_FreeArena(arena, PR_TRUE);
+ if (keyData)
+ SECITEM_ZfreeItem(keyData, PR_FALSE);
+ if (key)
+ PK11_FreeSymKey(key);
+ if (slot)
+ PK11_FreeSlot(slot);
+
+ return (rv == SECSuccess);
+ }
+*/
wtc 2011/09/02 22:31:08 Nit: please use #if 0 to comment out a block of co
zel 2011/09/03 01:52:22 Rewritten part.
+
+ bool EncryptWithSupplementalUserKey(const std::string& raw_data,
+ std::string* encryped_data) {
+ DCHECK(chromeos_user_logged_in_);
+
+ SECStatus rv = SECSuccess;
+ SECItem *params = NULL;
+ PK11SlotInfo* slot = NULL;
+ PK11SymKey *key = NULL;
+ PLArenaPool *arena = 0;
+ PK11Context *ctx = 0;
+ SDRResult sdrResult;
+ SECItem keyID;
+ SECItem data;
+ SECItem paddedData = { siBuffer, NULL, 0 };
+ SECItem tempResults = { siBuffer, NULL, 0 };
+ CK_MECHANISM_TYPE type = CKM_AES_CBC;
+
+ arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
+ if (!arena)
+ goto done;
+
+ slot = GetPublicNSSKeySlot();
+ if (!slot) {
+ rv = SECFailure;
+ goto done;
+ }
+
+ rv = PK11_Authenticate(slot, PR_TRUE, NULL);
+ if (rv != SECSuccess)
+ goto done;
+
+ keyID.type = siBuffer;
+ keyID.data = kSupplementalUserKeyId;
+ keyID.len = static_cast<int>(sizeof(kSupplementalUserKeyId));
+
+ // Find/generate AES key.
+ key = PK11_FindFixedKey(slot, type, &keyID, NULL);
+ if (!key) {
+ key = PK11_TokenKeyGen(slot, type, NULL,
+ 32, /* keysize in bytes*/
wtc 2011/09/02 22:31:08 This is just a comment: 256-bit AES is extremely s
+ &keyID, PR_TRUE, NULL);
+ if (key) {
+ rv = PK11_SetSymKeyNickname(key, kSupplementalKeyNickname);
+ if (rv != SECSuccess)
+ goto done;
+ }
+ }
+ if (!key) {
+ rv = SECFailure;
+ goto done;
+ }
+
+ params = PK11_GenerateNewParam(type, key);
+ if (!params) {
+ rv = SECFailure;
+ goto done;
+ }
+
+ ctx = PK11_CreateContextBySymKey(type, CKA_ENCRYPT, key, params);
+ if (!ctx) {
+ rv = SECFailure;
+ goto done;
+ }
+
+ data.type = siBuffer;
+ data.data = reinterpret_cast<unsigned char*>(
+ const_cast<char*>(raw_data.c_str()));
+ data.len = static_cast<int>(raw_data.length());
+
+ rv = PadBlock(&data, PK11_GetBlockSize(type, 0), &paddedData);
+ if (rv != SECSuccess)
+ goto done;
+
+ sdrResult.data.len = paddedData.len;
+ sdrResult.data.data = reinterpret_cast<unsigned char *>(
+ PORT_ArenaAlloc(arena, sdrResult.data.len));
+ rv = PK11_CipherOp(ctx, sdrResult.data.data,
+ reinterpret_cast<int*>(&sdrResult.data.len), sdrResult.data.len,
+ paddedData.data, paddedData.len);
+ if (rv != SECSuccess)
+ goto done;
+
+ PK11_Finalize(ctx);
+ sdrResult.keyid = keyID;
+
+ rv = PK11_ParamToAlgid(SEC_OID_AES_256_CBC, params, arena, &sdrResult.alg);
+ if (rv != SECSuccess)
+ goto done;
+
+ if (!SEC_ASN1EncodeItem(0, &tempResults, &sdrResult, g_encoding_template)) {
+ rv = SECFailure;
+ goto done;
+ }
+
+ if (rv == SECSuccess)
+ *encryped_data = std::string(
+ reinterpret_cast<const char*>(tempResults.data), tempResults.len);
+
+ done:
+ SECITEM_ZfreeItem(&paddedData, PR_FALSE);
+ SECITEM_ZfreeItem(&tempResults, PR_FALSE);
+ if (arena)
+ PORT_FreeArena(arena, PR_TRUE);
+ if (ctx)
+ PK11_DestroyContext(ctx, PR_TRUE);
+ if (params)
+ SECITEM_ZfreeItem(params, PR_TRUE);
+ if (key)
+ PK11_FreeSymKey(key);
+ if (slot)
+ PK11_FreeSlot(slot);
+
+ return (rv == SECSuccess);
+ }
+
+ bool DecryptWithSupplementalUserKey(const std::string& encrypted_data,
+ std::string* decrypted_data) {
+ DCHECK(chromeos_user_logged_in_);
+
+ SECStatus rv = SECSuccess;
+ PK11SlotInfo *slot = 0;
+ PK11SymKey *key = 0;
+ CK_MECHANISM_TYPE type;
+ SDRResult sdrResult;
+ SECItem *params = 0;
+ SECItem result = { siBuffer, NULL, 0 };
+ SECItem possibleResult = { siBuffer, NULL, 0 };
+ PLArenaPool *arena = 0;
+ void* cx = NULL;
+
+ SECItem data;
+ data.type = siBuffer;
+ data.data = reinterpret_cast<unsigned char*>(
+ const_cast<char*>(encrypted_data.c_str()));
+ data.len = static_cast<int>(encrypted_data.length());
+
+ arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
+ if (!arena) {
+ rv = SECFailure;
+ goto done;
+ }
+
+ // Decode the incoming data.
+ memset(&sdrResult, 0, sizeof sdrResult);
+ rv = SEC_QuickDERDecodeItem(arena, &sdrResult, g_encoding_template, &data);
+ if (rv != SECSuccess) // Invalid format.
+ goto done;
+
+ // Find the slot and key for the given keyid.
+ slot = GetPublicNSSKeySlot();
+ if (!slot) {
+ rv = SECFailure;
+ goto done;
+ }
+
+ // Get the parameter values from the data.
+ params = PK11_ParamFromAlgid(&sdrResult.alg);
+ if (!params) {
+ rv = SECFailure;
+ goto done;
+ }
+
+ // Use AES.
+ type = CKM_AES_CBC;
+ key = PK11_FindFixedKey(slot, type, &sdrResult.keyid, cx);
+ if (!key) {
+ rv = SECFailure;
+ } else {
+ rv = pk11Decrypt(slot, arena, type, key, params, &sdrResult.data,
+ &result);
+ }
+
+ // if the pad value was too small (1 or 2), then it's statistically
+ // 'likely' that (1 in 256) that we may not have the correct key.
+ // Check the other keys for a better match. If we find none, use
+ // this result.
+ if (rv == SECWouldBlock)
+ possibleResult = result;
+
+ // handle the case where your key indicies may have been broken.
+ if (rv != SECSuccess) {
+ PK11SymKey *keyList = PK11_ListFixedKeysInSlot(slot, NULL, cx);
+ PK11SymKey *testKey = NULL;
+ PK11SymKey *nextKey = NULL;
+
+ for (testKey = keyList; testKey; testKey = PK11_GetNextSymKey(testKey)) {
+ rv = pk11Decrypt(slot, arena, type, testKey, params,
+ &sdrResult.data, &result);
+ if (rv == SECSuccess)
+ break;
+
+ // found a close match. If it's our first remember it.
+ if (rv == SECWouldBlock) {
+ if (possibleResult.data) {
+ // this is unlikely but possible. If we hit this condition,
+ // we have no way of knowing which possibility to prefer.
+ // in this case we just match the key the application
+ // thought was the right one
+ SECITEM_ZfreeItem(&result, PR_FALSE);
+ } else {
+ possibleResult = result;
+ }
+ }
+ }
+ // free the list
+ for (testKey = keyList; testKey; testKey = nextKey) {
+ nextKey = PK11_GetNextSymKey(testKey);
+ PK11_FreeSymKey(testKey);
+ }
+ }
+
+ // we didn't find a better key, use the one with a small pad value
+ if ((rv != SECSuccess) && (possibleResult.data)) {
+ result = possibleResult;
+ possibleResult.data = NULL;
+ rv = SECSuccess;
+ }
+
+ if (rv == SECSuccess) {
+ *decrypted_data = std::string(reinterpret_cast<const char*>(result.data),
+ result.len);
+ }
+
+ done:
+ SECITEM_ZfreeItem(&result, PR_FALSE);
+ if (arena)
+ PORT_FreeArena(arena, PR_TRUE);
+ if (key)
+ PK11_FreeSymKey(key);
+ if (params)
+ SECITEM_ZfreeItem(params, PR_TRUE);
+ if (slot)
+ PK11_FreeSlot(slot);
+ if (possibleResult.data)
+ SECITEM_ZfreeItem(&possibleResult, PR_FALSE);
+
+ return (rv == SECSuccess);
+ }
#endif // defined(OS_CHROMEOS)
@@ -702,6 +1154,17 @@
return g_nss_singleton.Get().EnsureTPMTokenReady();
}
+bool EncryptWithSupplementalUserKey(const std::string& data,
+ std::string* encryped_data) {
+ return g_nss_singleton.Get().EncryptWithSupplementalUserKey(data,
+ encryped_data);
+}
+
+bool DecryptWithSupplementalUserKey(const std::string& encryped_data,
+ std::string* raw_data) {
+ return g_nss_singleton.Get().DecryptWithSupplementalUserKey(encryped_data,
+ raw_data);
+}
#endif // defined(OS_CHROMEOS)
// TODO(port): Implement this more simply. We can convert by subtracting an
« crypto/nss_util.h ('K') | « crypto/nss_util.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698