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

Side by Side 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, 3 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 unified diff | Download patch | Annotate | Revision Log
« crypto/nss_util.h ('K') | « crypto/nss_util.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "crypto/nss_util.h" 5 #include "crypto/nss_util.h"
6 #include "crypto/nss_util_internal.h" 6 #include "crypto/nss_util_internal.h"
7 7
8 #include <nss.h> 8 #include <nss.h>
9 #include <plarena.h> 9 #include <plarena.h>
10 #include <prerror.h> 10 #include <prerror.h>
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
76 return dir; 76 return dir;
77 } 77 }
78 dir = dir.AppendASCII(".pki").AppendASCII("nssdb"); 78 dir = dir.AppendASCII(".pki").AppendASCII("nssdb");
79 if (!file_util::CreateDirectory(dir)) { 79 if (!file_util::CreateDirectory(dir)) {
80 LOG(ERROR) << "Failed to create " << dir.value() << " directory."; 80 LOG(ERROR) << "Failed to create " << dir.value() << " directory.";
81 dir.clear(); 81 dir.clear();
82 } 82 }
83 return dir; 83 return dir;
84 } 84 }
85 85
86 #if defined(OS_CHROMEOS)
87
88 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
89 0xCC, 0x13, 0x19, 0xDE, 0x75, 0x5E, 0xFE, 0x00,
90 0x5E, 0x71, 0xD4, 0xA6, 0x00, 0x00, 0x00, 0xCC
91 };
92
93 const char kSupplementalKeyNickname[] = "ChromeOS_SupplementalUserKey";
94
95 struct SDRResult
96 {
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
97 SECItem keyid;
98 SECAlgorithmID alg;
99 SECItem data;
100 };
101 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.
102
103 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
104
105 static SEC_ASN1Template g_encoding_template[] = {
106 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof (SDRResult) },
107 { SEC_ASN1_OCTET_STRING, offsetof(SDRResult, keyid) },
108 { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(SDRResult, alg),
109 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
110 { SEC_ASN1_OCTET_STRING, offsetof(SDRResult, data) },
111 { 0 }
112 };
113
114 // Local utility functions for padding/unpadding an incoming data block
115 // to the mechanism block size.
116
117 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.
118 SECStatus rv = SECSuccess;
119 unsigned int padLength;
120 unsigned int i;
121
122 result->data = 0;
123 result->len = 0;
124
125 // This algorithm always adds to the block (to indicate the number
126 // of pad bytes). So allocate a block large enough.
127 padLength = blockSize - (data->len % blockSize);
128 result->len = data->len + padLength;
129 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.
130
131 // Copy the data
132 PORT_Memcpy(result->data, data->data, data->len);
133
134 // Add the pad values
135 for(i = data->len; i < result->len; i++)
136 result->data[i] = (unsigned char) padLength;
137
138 return rv;
139 }
140
141 SECStatus UnpadBlock(SECItem *data, unsigned int blockSize, SECItem *result) {
142 SECStatus rv = SECSuccess;
143 unsigned int padLength;
144 unsigned int i;
145
146 result->data = 0;
147 result->len = 0;
148
149 // Remove the padding from the end if the input data.
150 if (data->len == 0 || data->len % blockSize != 0) {
151 rv = SECFailure;
152 goto done;
153 }
154
155 padLength = data->data[data->len-1];
156 if (padLength > blockSize) {
157 rv = SECFailure;
158 goto done;
159 }
160
161 // Verify padding.
162 for (i = data->len - padLength; i < data->len; i++) {
163 if (data->data[i] != padLength) {
164 rv = SECFailure;
165 goto done;
166 }
167 }
168
169 result->len = data->len - padLength;
170 result->data = (unsigned char *) PORT_Alloc(result->len);
171 if (!result->data) {
172 rv = SECFailure;
173 goto done;
174 }
175
176 PORT_Memcpy(result->data, data->data, result->len);
177
178 if (padLength < 2) {
179 return SECWouldBlock;
180 }
181
182 done:
183 return rv;
184 }
185
186 // decrypt a block
187 SECStatus pk11Decrypt(PK11SlotInfo *slot, PLArenaPool *arena,
188 CK_MECHANISM_TYPE type, PK11SymKey *key,
189 SECItem *params, SECItem *in, SECItem *result) {
190 PK11Context *ctx = 0;
191 SECItem paddedResult;
192 SECStatus rv;
193
194 paddedResult.len = 0;
195 paddedResult.data = 0;
196
197 ctx = PK11_CreateContextBySymKey(type, CKA_DECRYPT, key, params);
198 if (!ctx) {
199 rv = SECFailure;
200 goto done;
201 }
202
203 paddedResult.len = in->len;
204 paddedResult.data = reinterpret_cast<unsigned char *>(
205 PORT_ArenaAlloc(arena, paddedResult.len));
206
207 rv = PK11_CipherOp(ctx, paddedResult.data,
208 reinterpret_cast<int*>(&paddedResult.len), paddedResult.len,
209 in->data, in->len);
210 if (rv != SECSuccess)
211 goto done;
212
213 PK11_Finalize(ctx);
214
215 // Remove the padding.
216 rv = UnpadBlock(&paddedResult, PK11_GetBlockSize(type, 0), result);
217 if (rv)
218 goto done;
219
220 done:
221 if (ctx)
222 PK11_DestroyContext(ctx, PR_TRUE);
223 return rv;
224 }
wtc 2011/09/02 22:31:08 If these functions are copied from NSS or Mozilla,
zel 2011/09/03 01:52:22 Removed.
225 #endif
226
227
wtc 2011/09/02 22:31:08 Nit: remove one blank line.
86 // On non-chromeos platforms, return the default config directory. 228 // On non-chromeos platforms, return the default config directory.
87 // On chromeos, return a read-only directory with fake root CA certs for testing 229 // On chromeos, return a read-only directory with fake root CA certs for testing
88 // (which will not exist on non-testing images). These root CA certs are used 230 // (which will not exist on non-testing images). These root CA certs are used
89 // by the local Google Accounts server mock we use when testing our login code. 231 // by the local Google Accounts server mock we use when testing our login code.
90 // If this directory is not present, NSS_Init() will fail. It is up to the 232 // If this directory is not present, NSS_Init() will fail. It is up to the
91 // caller to failover to NSS_NoDB_Init() at that point. 233 // caller to failover to NSS_NoDB_Init() at that point.
92 FilePath GetInitialConfigDirectory() { 234 FilePath GetInitialConfigDirectory() {
93 #if defined(OS_CHROMEOS) 235 #if defined(OS_CHROMEOS)
94 return FilePath(kReadOnlyCertDB); 236 return FilePath(kReadOnlyCertDB);
95 #else 237 #else
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after
280 422
281 bool IsTPMTokenReady() { 423 bool IsTPMTokenReady() {
282 return tpm_slot_ != NULL; 424 return tpm_slot_ != NULL;
283 } 425 }
284 426
285 PK11SlotInfo* GetTPMSlot() { 427 PK11SlotInfo* GetTPMSlot() {
286 std::string token_name; 428 std::string token_name;
287 GetTPMTokenInfo(&token_name, NULL); 429 GetTPMTokenInfo(&token_name, NULL);
288 return FindSlotWithTokenName(token_name); 430 return FindSlotWithTokenName(token_name);
289 } 431 }
290 432 /*
433 bool GetSupplementalUserKey(std::string* user_key) {
434 OpenPersistentNSSDB();
435
436 SECStatus rv = SECSuccess;
437 PK11SlotInfo* slot = NULL;
438 PK11SymKey *key = NULL;
439 SECItem* keyData = NULL;
440 SECItem keyID;
441 CK_MECHANISM_TYPE type = CKM_DES3_CBC;
442 PLArenaPool *arena = 0;
443
444 arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
445 if (!arena)
446 goto done;
447
448 slot = GetPublicNSSKeySlot();
449 if (!slot) {
450 rv = SECFailure;
451 goto done;
452 }
453
454 rv = PK11_Authenticate(slot, PR_TRUE, NULL);
455 if (rv != SECSuccess)
456 goto done;
457
458 keyID.type = siBuffer;
459 keyID.data = kSupplementalUserKeyId;
460 keyID.len = static_cast<int>(sizeof(kSupplementalUserKeyId));
461
462 // Find/generate AES key.
463 key = PK11_FindFixedKey(slot, type, &keyID, NULL);
464 if (!key) {
465
466 key = PK11_TokenKeyGen(slot, type, 0, 0, &keyID, PR_TRUE, NULL);
467 if (key) {
468 rv = PK11_SetSymKeyNickname(key, kSupplementalKeyNickname);
469 if (rv != SECSuccess)
470 goto done;
471 } else {
472 int error = PORT_GetError();
473 LOG(WARNING) << "Got error: " << error;
474 }
475 }
476
477 if (!key) {
478 rv = SECFailure;
479 goto done;
480 }
481
482 keyData = PK11_GetKeyData(key);
483 if (!keyData) {
484 rv = SECFailure;
485 goto done;
486 }
487
488 *user_key = std::string(
489 reinterpret_cast<const char*>(keyData->data), keyData->len);
490
491 done:
492 if (arena)
493 PORT_FreeArena(arena, PR_TRUE);
494 if (keyData)
495 SECITEM_ZfreeItem(keyData, PR_FALSE);
496 if (key)
497 PK11_FreeSymKey(key);
498 if (slot)
499 PK11_FreeSlot(slot);
500
501 return (rv == SECSuccess);
502 }
503 */
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.
504
505 bool EncryptWithSupplementalUserKey(const std::string& raw_data,
506 std::string* encryped_data) {
507 DCHECK(chromeos_user_logged_in_);
508
509 SECStatus rv = SECSuccess;
510 SECItem *params = NULL;
511 PK11SlotInfo* slot = NULL;
512 PK11SymKey *key = NULL;
513 PLArenaPool *arena = 0;
514 PK11Context *ctx = 0;
515 SDRResult sdrResult;
516 SECItem keyID;
517 SECItem data;
518 SECItem paddedData = { siBuffer, NULL, 0 };
519 SECItem tempResults = { siBuffer, NULL, 0 };
520 CK_MECHANISM_TYPE type = CKM_AES_CBC;
521
522 arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
523 if (!arena)
524 goto done;
525
526 slot = GetPublicNSSKeySlot();
527 if (!slot) {
528 rv = SECFailure;
529 goto done;
530 }
531
532 rv = PK11_Authenticate(slot, PR_TRUE, NULL);
533 if (rv != SECSuccess)
534 goto done;
535
536 keyID.type = siBuffer;
537 keyID.data = kSupplementalUserKeyId;
538 keyID.len = static_cast<int>(sizeof(kSupplementalUserKeyId));
539
540 // Find/generate AES key.
541 key = PK11_FindFixedKey(slot, type, &keyID, NULL);
542 if (!key) {
543 key = PK11_TokenKeyGen(slot, type, NULL,
544 32, /* keysize in bytes*/
wtc 2011/09/02 22:31:08 This is just a comment: 256-bit AES is extremely s
545 &keyID, PR_TRUE, NULL);
546 if (key) {
547 rv = PK11_SetSymKeyNickname(key, kSupplementalKeyNickname);
548 if (rv != SECSuccess)
549 goto done;
550 }
551 }
552 if (!key) {
553 rv = SECFailure;
554 goto done;
555 }
556
557 params = PK11_GenerateNewParam(type, key);
558 if (!params) {
559 rv = SECFailure;
560 goto done;
561 }
562
563 ctx = PK11_CreateContextBySymKey(type, CKA_ENCRYPT, key, params);
564 if (!ctx) {
565 rv = SECFailure;
566 goto done;
567 }
568
569 data.type = siBuffer;
570 data.data = reinterpret_cast<unsigned char*>(
571 const_cast<char*>(raw_data.c_str()));
572 data.len = static_cast<int>(raw_data.length());
573
574 rv = PadBlock(&data, PK11_GetBlockSize(type, 0), &paddedData);
575 if (rv != SECSuccess)
576 goto done;
577
578 sdrResult.data.len = paddedData.len;
579 sdrResult.data.data = reinterpret_cast<unsigned char *>(
580 PORT_ArenaAlloc(arena, sdrResult.data.len));
581 rv = PK11_CipherOp(ctx, sdrResult.data.data,
582 reinterpret_cast<int*>(&sdrResult.data.len), sdrResult.data.len,
583 paddedData.data, paddedData.len);
584 if (rv != SECSuccess)
585 goto done;
586
587 PK11_Finalize(ctx);
588 sdrResult.keyid = keyID;
589
590 rv = PK11_ParamToAlgid(SEC_OID_AES_256_CBC, params, arena, &sdrResult.alg);
591 if (rv != SECSuccess)
592 goto done;
593
594 if (!SEC_ASN1EncodeItem(0, &tempResults, &sdrResult, g_encoding_template)) {
595 rv = SECFailure;
596 goto done;
597 }
598
599 if (rv == SECSuccess)
600 *encryped_data = std::string(
601 reinterpret_cast<const char*>(tempResults.data), tempResults.len);
602
603 done:
604 SECITEM_ZfreeItem(&paddedData, PR_FALSE);
605 SECITEM_ZfreeItem(&tempResults, PR_FALSE);
606 if (arena)
607 PORT_FreeArena(arena, PR_TRUE);
608 if (ctx)
609 PK11_DestroyContext(ctx, PR_TRUE);
610 if (params)
611 SECITEM_ZfreeItem(params, PR_TRUE);
612 if (key)
613 PK11_FreeSymKey(key);
614 if (slot)
615 PK11_FreeSlot(slot);
616
617 return (rv == SECSuccess);
618 }
619
620 bool DecryptWithSupplementalUserKey(const std::string& encrypted_data,
621 std::string* decrypted_data) {
622 DCHECK(chromeos_user_logged_in_);
623
624 SECStatus rv = SECSuccess;
625 PK11SlotInfo *slot = 0;
626 PK11SymKey *key = 0;
627 CK_MECHANISM_TYPE type;
628 SDRResult sdrResult;
629 SECItem *params = 0;
630 SECItem result = { siBuffer, NULL, 0 };
631 SECItem possibleResult = { siBuffer, NULL, 0 };
632 PLArenaPool *arena = 0;
633 void* cx = NULL;
634
635 SECItem data;
636 data.type = siBuffer;
637 data.data = reinterpret_cast<unsigned char*>(
638 const_cast<char*>(encrypted_data.c_str()));
639 data.len = static_cast<int>(encrypted_data.length());
640
641 arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
642 if (!arena) {
643 rv = SECFailure;
644 goto done;
645 }
646
647 // Decode the incoming data.
648 memset(&sdrResult, 0, sizeof sdrResult);
649 rv = SEC_QuickDERDecodeItem(arena, &sdrResult, g_encoding_template, &data);
650 if (rv != SECSuccess) // Invalid format.
651 goto done;
652
653 // Find the slot and key for the given keyid.
654 slot = GetPublicNSSKeySlot();
655 if (!slot) {
656 rv = SECFailure;
657 goto done;
658 }
659
660 // Get the parameter values from the data.
661 params = PK11_ParamFromAlgid(&sdrResult.alg);
662 if (!params) {
663 rv = SECFailure;
664 goto done;
665 }
666
667 // Use AES.
668 type = CKM_AES_CBC;
669 key = PK11_FindFixedKey(slot, type, &sdrResult.keyid, cx);
670 if (!key) {
671 rv = SECFailure;
672 } else {
673 rv = pk11Decrypt(slot, arena, type, key, params, &sdrResult.data,
674 &result);
675 }
676
677 // if the pad value was too small (1 or 2), then it's statistically
678 // 'likely' that (1 in 256) that we may not have the correct key.
679 // Check the other keys for a better match. If we find none, use
680 // this result.
681 if (rv == SECWouldBlock)
682 possibleResult = result;
683
684 // handle the case where your key indicies may have been broken.
685 if (rv != SECSuccess) {
686 PK11SymKey *keyList = PK11_ListFixedKeysInSlot(slot, NULL, cx);
687 PK11SymKey *testKey = NULL;
688 PK11SymKey *nextKey = NULL;
689
690 for (testKey = keyList; testKey; testKey = PK11_GetNextSymKey(testKey)) {
691 rv = pk11Decrypt(slot, arena, type, testKey, params,
692 &sdrResult.data, &result);
693 if (rv == SECSuccess)
694 break;
695
696 // found a close match. If it's our first remember it.
697 if (rv == SECWouldBlock) {
698 if (possibleResult.data) {
699 // this is unlikely but possible. If we hit this condition,
700 // we have no way of knowing which possibility to prefer.
701 // in this case we just match the key the application
702 // thought was the right one
703 SECITEM_ZfreeItem(&result, PR_FALSE);
704 } else {
705 possibleResult = result;
706 }
707 }
708 }
709 // free the list
710 for (testKey = keyList; testKey; testKey = nextKey) {
711 nextKey = PK11_GetNextSymKey(testKey);
712 PK11_FreeSymKey(testKey);
713 }
714 }
715
716 // we didn't find a better key, use the one with a small pad value
717 if ((rv != SECSuccess) && (possibleResult.data)) {
718 result = possibleResult;
719 possibleResult.data = NULL;
720 rv = SECSuccess;
721 }
722
723 if (rv == SECSuccess) {
724 *decrypted_data = std::string(reinterpret_cast<const char*>(result.data),
725 result.len);
726 }
727
728 done:
729 SECITEM_ZfreeItem(&result, PR_FALSE);
730 if (arena)
731 PORT_FreeArena(arena, PR_TRUE);
732 if (key)
733 PK11_FreeSymKey(key);
734 if (params)
735 SECITEM_ZfreeItem(params, PR_TRUE);
736 if (slot)
737 PK11_FreeSlot(slot);
738 if (possibleResult.data)
739 SECITEM_ZfreeItem(&possibleResult, PR_FALSE);
740
741 return (rv == SECSuccess);
742 }
291 #endif // defined(OS_CHROMEOS) 743 #endif // defined(OS_CHROMEOS)
292 744
293 745
294 bool OpenTestNSSDB(const FilePath& path, const char* description) { 746 bool OpenTestNSSDB(const FilePath& path, const char* description) {
295 test_slot_ = OpenUserDB(path, description); 747 test_slot_ = OpenUserDB(path, description);
296 return !!test_slot_; 748 return !!test_slot_;
297 } 749 }
298 750
299 void CloseTestNSSDB() { 751 void CloseTestNSSDB() {
300 if (test_slot_) { 752 if (test_slot_) {
(...skipping 394 matching lines...) Expand 10 before | Expand all | Expand 10 after
695 } 1147 }
696 1148
697 bool IsTPMTokenReady() { 1149 bool IsTPMTokenReady() {
698 return g_nss_singleton.Get().IsTPMTokenReady(); 1150 return g_nss_singleton.Get().IsTPMTokenReady();
699 } 1151 }
700 1152
701 bool EnsureTPMTokenReady() { 1153 bool EnsureTPMTokenReady() {
702 return g_nss_singleton.Get().EnsureTPMTokenReady(); 1154 return g_nss_singleton.Get().EnsureTPMTokenReady();
703 } 1155 }
704 1156
1157 bool EncryptWithSupplementalUserKey(const std::string& data,
1158 std::string* encryped_data) {
1159 return g_nss_singleton.Get().EncryptWithSupplementalUserKey(data,
1160 encryped_data);
1161 }
1162
1163 bool DecryptWithSupplementalUserKey(const std::string& encryped_data,
1164 std::string* raw_data) {
1165 return g_nss_singleton.Get().DecryptWithSupplementalUserKey(encryped_data,
1166 raw_data);
1167 }
705 #endif // defined(OS_CHROMEOS) 1168 #endif // defined(OS_CHROMEOS)
706 1169
707 // TODO(port): Implement this more simply. We can convert by subtracting an 1170 // TODO(port): Implement this more simply. We can convert by subtracting an
708 // offset (the difference between NSPR's and base::Time's epochs). 1171 // offset (the difference between NSPR's and base::Time's epochs).
709 base::Time PRTimeToBaseTime(PRTime prtime) { 1172 base::Time PRTimeToBaseTime(PRTime prtime) {
710 PRExplodedTime prxtime; 1173 PRExplodedTime prxtime;
711 PR_ExplodeTime(prtime, PR_GMTParameters, &prxtime); 1174 PR_ExplodeTime(prtime, PR_GMTParameters, &prxtime);
712 1175
713 base::Time::Exploded exploded; 1176 base::Time::Exploded exploded;
714 exploded.year = prxtime.tm_year; 1177 exploded.year = prxtime.tm_year;
(...skipping 10 matching lines...) Expand all
725 1188
726 PK11SlotInfo* GetPublicNSSKeySlot() { 1189 PK11SlotInfo* GetPublicNSSKeySlot() {
727 return g_nss_singleton.Get().GetPublicNSSKeySlot(); 1190 return g_nss_singleton.Get().GetPublicNSSKeySlot();
728 } 1191 }
729 1192
730 PK11SlotInfo* GetPrivateNSSKeySlot() { 1193 PK11SlotInfo* GetPrivateNSSKeySlot() {
731 return g_nss_singleton.Get().GetPrivateNSSKeySlot(); 1194 return g_nss_singleton.Get().GetPrivateNSSKeySlot();
732 } 1195 }
733 1196
734 } // namespace crypto 1197 } // namespace crypto
OLDNEW
« 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