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

Side by Side Diff: net/base/keygen_handler_nss.cc

Issue 261035: Adds support for the <keygen> tag for client certificate enrollment under Lin... (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: '' Created 11 years, 2 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
Property Changes:
Name: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/base/keygen_handler.h"
6
7 // Work around https://bugzilla.mozilla.org/show_bug.cgi?id=455424
8 // until NSS 3.12.2 comes out and we update to it.
9 #define Lock FOO_NSS_Lock
10 #include <pk11pub.h>
11 #include <secmod.h>
12 #include <ssl.h>
13 #include <nssb64.h> // NSSBase64_EncodeItem()
14 #include <secder.h> // DER_Encode()
15 #include <cryptohi.h> // SEC_DerSignData()
16 #include <keyhi.h> // SECKEY_CreateSubjectPublicKeyInfo()
17 #undef Lock
18
19 #include "base/nss_init.h"
20 #include "base/logging.h"
21
22 namespace net {
23
24 const int64 DEFAULT_RSA_PUBLIC_EXPONENT = 0x10001;
25
26 // Template for creating the signed public key structure to be sent to the CA.
27 DERTemplate SECAlgorithmIDTemplate[] = {
28 { DER_SEQUENCE,
29 0, NULL, sizeof(SECAlgorithmID) },
30 { DER_OBJECT_ID,
31 offsetof(SECAlgorithmID, algorithm), },
32 { DER_OPTIONAL | DER_ANY,
33 offsetof(SECAlgorithmID, parameters), },
34 { 0, }
35 };
36
37 DERTemplate CERTSubjectPublicKeyInfoTemplate[] = {
38 { DER_SEQUENCE,
39 0, NULL, sizeof(CERTSubjectPublicKeyInfo) },
40 { DER_INLINE,
41 offsetof(CERTSubjectPublicKeyInfo, algorithm),
42 SECAlgorithmIDTemplate, },
43 { DER_BIT_STRING,
44 offsetof(CERTSubjectPublicKeyInfo, subjectPublicKey), },
45 { 0, }
46 };
47
48 DERTemplate CERTPublicKeyAndChallengeTemplate[] = {
49 { DER_SEQUENCE,
50 0, NULL, sizeof(CERTPublicKeyAndChallenge) },
51 { DER_ANY,
52 offsetof(CERTPublicKeyAndChallenge, spki), },
53 { DER_IA5_STRING,
54 offsetof(CERTPublicKeyAndChallenge, challenge), },
55 { 0, }
56 };
57
58 // This maps displayed strings indicating level of keysecurity in the <keygen>
59 // menu to the key size in bits.
60 // TODO(gauravsh): Should this mapping be moved else where?
61 int RSAkeySizeMap[] = {2048, 1024};
62
63 KeygenHandler::KeygenHandler(int key_size_index,
64 const std::string& challenge)
65 : key_size_index_(key_size_index),
66 challenge_(challenge) {
67 }
68
69 // This function is largely copied from the Firefox's
70 // <keygen> implementation in security/manager/ssl/src/nsKeygenHandler.cpp
71 // FIXME(gauravsh): Do we need a copy of the Mozilla license here?
72
73 std::string KeygenHandler::GenKeyAndSignChallenge() {
74 // Key pair generation mechanism - only RSA is supported at present.
75 PRUint32 keyGenMechanism = CKM_RSA_PKCS_KEY_PAIR_GEN; // from nss/pkcs11t.h
76 char *keystring = NULL; // Temporary store for result/
77
78 // Temporary structures used for generating the result
79 // in the right format.
80 PK11SlotInfo *slot = NULL;
81 PK11RSAGenParams rsaKeyGenParams; // Keygen parameters.
82 SECOidTag algTag; // used by SEC_DerSignData().
83 SECKEYPrivateKey *privateKey = NULL;
84 SECKEYPublicKey *publicKey = NULL;
85 CERTSubjectPublicKeyInfo *spkInfo = NULL;
86 PRArenaPool *arena = NULL;
87 SECStatus sec_rv =SECFailure;
88 SECItem spkiItem;
89 SECItem pkacItem;
90 SECItem signedItem;
91 CERTPublicKeyAndChallenge pkac;
92 void *keyGenParams;
93 pkac.challenge.data = NULL;
94 bool isSuccess = true; // Set to false as soon as a step fails.
95
96 std::string result_blob; // the result.
97
98 // Ensure NSS is initialized.
99 base::EnsureNSSInit();
100
101 slot = PK11_GetInternalKeySlot();
102 if (!slot) {
103 LOG(ERROR) << "Couldn't get Internal key slot!";
104 isSuccess = false;
105 goto failure;
106 }
107
108 switch (keyGenMechanism) {
109 case CKM_RSA_PKCS_KEY_PAIR_GEN:
110 rsaKeyGenParams.keySizeInBits = RSAkeySizeMap[key_size_index_];
111 rsaKeyGenParams.pe = DEFAULT_RSA_PUBLIC_EXPONENT;
112 keyGenParams = &rsaKeyGenParams;
113
114 algTag = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION; // from <nss/secoidt.h>.
115 break;
116 default:
117 // TODO(gauravsh): If we ever support other mechanisms,
118 // this can be changed.
119 LOG(ERROR) << "Only RSA keygen mechanism is supported";
120 isSuccess = false;
121 goto failure;
122 break;
123 }
124
125 // Need to make sure that the token was initialized.
126 // Assume a null password.
127 sec_rv = PK11_Authenticate(slot, PR_TRUE, NULL);
128 if (SECSuccess != sec_rv) {
129 LOG(ERROR) << "Couldn't initialze PK11 token!";
130 isSuccess = false;
131 goto failure;
132 }
133
134 LOG(INFO) << "Creating key pair...";
135 privateKey = PK11_GenerateKeyPair(slot,
136 keyGenMechanism,
137 keyGenParams,
138 &publicKey,
139 PR_TRUE, // isPermanent?
140 PR_TRUE, // isSensitive?
141 NULL);
142 LOG(INFO) << "done.";
143
144 if (!privateKey) {
145 LOG(INFO) << "Generation of Keypair failed!";
146 isSuccess = false;
147 goto failure;
148 }
149
150 // The CA expects the signed public key in a specific format
151 // Let's create that now.
152
153 // Create a subject public key info from the public key.
154 spkInfo = SECKEY_CreateSubjectPublicKeyInfo(publicKey);
155 if (!spkInfo) {
156 LOG(ERROR) << "Couldn't create SubjectPublicKeyInfo from public key";
157 isSuccess = false;
158 goto failure;
159 }
160
161 // Temporary work store used by NSS.
162 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
163 if (!arena) {
164 LOG(ERROR) << "PORT_NewArena: Couldn't allocate memory";
165 isSuccess = false;
166 goto failure;
167 }
168
169 // DER encode the whole subjectPublicKeyInfo.
170 sec_rv = DER_Encode(arena, &spkiItem, CERTSubjectPublicKeyInfoTemplate,
171 spkInfo);
172 if (SECSuccess != sec_rv) {
173 LOG(ERROR) << "Couldn't DER Encode subjectPublicKeyInfo";
174 isSuccess = false;
175 goto failure;
176 }
177
178 // Set up the PublicKeyAndChallenge data structure, then DER encode it.
179 pkac.spki = spkiItem;
180 pkac.challenge.len = challenge_.length();
181 pkac.challenge.data = (unsigned char *)strdup(challenge_.c_str());
182 if (!pkac.challenge.data) {
183 LOG(ERROR) << "Out of memory while making a copy of challenge data";
184 isSuccess = false;
185 goto failure;
186 }
187 sec_rv = DER_Encode(arena, &pkacItem, CERTPublicKeyAndChallengeTemplate,
188 &pkac);
189 if (SECSuccess != sec_rv) {
190 LOG(ERROR) << "Couldn't DER Encode PublicKeyAndChallenge";
191 isSuccess = false;
192 goto failure;
193 }
194
195 // Sign the DER encoded PublicKeyAndChallenge.
196 sec_rv = SEC_DerSignData(arena, &signedItem, pkacItem.data, pkacItem.len,
197 privateKey, algTag);
198 if (SECSuccess != sec_rv) {
199 LOG(ERROR) << "Couldn't sign the DER encoded PublicKeyandChallenge";
200 isSuccess = false;
201 goto failure;
202 }
203
204 // Convert the signed public key and challenge into base64/ascii.
205 keystring = NSSBase64_EncodeItem(arena,
206 NULL, // NSS will allocate a buffer for us.
207 0,
208 &signedItem);
209 if (!keystring) {
210 LOG(ERROR) << "Couldn't convert signed public key into base64";
211 isSuccess = false;
212 goto failure;
213 }
214
215 result_blob = keystring;
216
217 failure:
218 if (!isSuccess) {
219 LOG(ERROR) << "SSL Keygen failed!";
220 } else {
221 LOG(INFO) << "SSl Keygen succeeded!";
222 }
223
224 // Do cleanups
225 if (privateKey) {
226 // TODO(gauravsh): We still need to maintain the private key because it's
227 // used for certificate enrollment checks.
228
229 // PK11_DestroyTokenObject(privateKey->pkcs11Slot,privateKey->pkcs11ID);
230 // SECKEY_DestroyPrivateKey(privateKey);
231 }
232
233 if (publicKey) {
234 PK11_DestroyTokenObject(publicKey->pkcs11Slot, publicKey->pkcs11ID);
235 }
236 if (spkInfo) {
237 SECKEY_DestroySubjectPublicKeyInfo(spkInfo);
238 }
239 if (publicKey) {
240 SECKEY_DestroyPublicKey(publicKey);
241 }
242 if (arena) {
243 PORT_FreeArena(arena, PR_TRUE);
244 }
245 if (slot != NULL) {
246 PK11_FreeSlot(slot);
247 }
248 if (pkac.challenge.data) {
249 free(pkac.challenge.data);
250 }
251
252 return (isSuccess ? result_blob : std::string());
253 }
254
255 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698