| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 * |
| 3 // found in the LICENSE file. | 3 * ***** BEGIN LICENSE BLOCK ***** |
| 4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 |
| 5 * |
| 6 * The contents of this file are subject to the Mozilla Public License Version |
| 7 * 1.1 (the "License"); you may not use this file except in compliance with |
| 8 * the License. You may obtain a copy of the License at |
| 9 * http://www.mozilla.org/MPL/ |
| 10 * |
| 11 * Software distributed under the License is distributed on an "AS IS" basis, |
| 12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License |
| 13 * for the specific language governing rights and limitations under the |
| 14 * License. |
| 15 * |
| 16 * The Original Code is mozilla.org code. |
| 17 * |
| 18 * The Initial Developer of the Original Code is |
| 19 * Netscape Communications Corporation. |
| 20 * Portions created by the Initial Developer are Copyright (C) 1998 |
| 21 * the Initial Developer. All Rights Reserved. |
| 22 * |
| 23 * Contributor(s): |
| 24 * Vipul Gupta <vipul.gupta@sun.com> |
| 25 * Douglas Stebila <douglas@stebila.ca> |
| 26 * |
| 27 * Alternatively, the contents of this file may be used under the terms of |
| 28 * either the GNU General Public License Version 2 or later (the "GPL"), or |
| 29 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), |
| 30 * in which case the provisions of the GPL or the LGPL are applicable instead |
| 31 * of those above. If you wish to allow use of your version of this file only |
| 32 * under the terms of either the GPL or the LGPL, and not to allow others to |
| 33 * use your version of this file under the terms of the MPL, indicate your |
| 34 * decision by deleting the provisions above and replace them with the notice |
| 35 * and other provisions required by the GPL or the LGPL. If you do not delete |
| 36 * the provisions above, a recipient may use your version of this file under |
| 37 * the terms of any one of the MPL, the GPL or the LGPL. |
| 38 * |
| 39 * ***** END LICENSE BLOCK ***** */ |
| 4 | 40 |
| 5 #include "net/base/keygen_handler.h" | 41 #include "net/third_party/mozilla_security_manager/nsKeygenHandler.h" |
| 6 | 42 |
| 7 #include <pk11pub.h> | 43 #include <pk11pub.h> |
| 8 #include <secmod.h> | 44 #include <secmod.h> |
| 9 #include <ssl.h> | |
| 10 #include <secder.h> // DER_Encode() | 45 #include <secder.h> // DER_Encode() |
| 11 #include <cryptohi.h> // SEC_DerSignData() | 46 #include <cryptohi.h> // SEC_DerSignData() |
| 12 #include <keyhi.h> // SECKEY_CreateSubjectPublicKeyInfo() | 47 #include <keyhi.h> // SECKEY_CreateSubjectPublicKeyInfo() |
| 13 | 48 |
| 14 #include "base/base64.h" | 49 #include "base/base64.h" |
| 15 #include "base/nss_util_internal.h" | 50 #include "base/nss_util_internal.h" |
| 16 #include "base/nss_util.h" | 51 #include "base/nss_util.h" |
| 17 #include "base/logging.h" | 52 #include "base/logging.h" |
| 53 #include "net/base/keygen_handler.h" |
| 18 | 54 |
| 19 namespace net { | 55 namespace { |
| 20 | |
| 21 const int64 DEFAULT_RSA_PUBLIC_EXPONENT = 0x10001; | |
| 22 | 56 |
| 23 // Template for creating the signed public key structure to be sent to the CA. | 57 // Template for creating the signed public key structure to be sent to the CA. |
| 24 DERTemplate SECAlgorithmIDTemplate[] = { | 58 DERTemplate SECAlgorithmIDTemplate[] = { |
| 25 { DER_SEQUENCE, | 59 { DER_SEQUENCE, |
| 26 0, NULL, sizeof(SECAlgorithmID) }, | 60 0, NULL, sizeof(SECAlgorithmID) }, |
| 27 { DER_OBJECT_ID, | 61 { DER_OBJECT_ID, |
| 28 offsetof(SECAlgorithmID, algorithm), }, | 62 offsetof(SECAlgorithmID, algorithm), }, |
| 29 { DER_OPTIONAL | DER_ANY, | 63 { DER_OPTIONAL | DER_ANY, |
| 30 offsetof(SECAlgorithmID, parameters), }, | 64 offsetof(SECAlgorithmID, parameters), }, |
| 31 { 0, } | 65 { 0, } |
| (...skipping 15 matching lines...) Expand all Loading... |
| 47 0, NULL, sizeof(CERTPublicKeyAndChallenge) }, | 81 0, NULL, sizeof(CERTPublicKeyAndChallenge) }, |
| 48 { DER_ANY, | 82 { DER_ANY, |
| 49 offsetof(CERTPublicKeyAndChallenge, spki), }, | 83 offsetof(CERTPublicKeyAndChallenge, spki), }, |
| 50 { DER_IA5_STRING, | 84 { DER_IA5_STRING, |
| 51 offsetof(CERTPublicKeyAndChallenge, challenge), }, | 85 offsetof(CERTPublicKeyAndChallenge, challenge), }, |
| 52 { 0, } | 86 { 0, } |
| 53 }; | 87 }; |
| 54 | 88 |
| 55 void StoreKeyLocationInCache(const SECItem& public_key_info, | 89 void StoreKeyLocationInCache(const SECItem& public_key_info, |
| 56 PK11SlotInfo *slot) { | 90 PK11SlotInfo *slot) { |
| 57 KeygenHandler::Cache* cache = KeygenHandler::Cache::GetInstance(); | 91 net::KeygenHandler::Cache* cache = net::KeygenHandler::Cache::GetInstance(); |
| 58 KeygenHandler::KeyLocation key_location; | 92 net::KeygenHandler::KeyLocation key_location; |
| 59 const char* slot_name = PK11_GetSlotName(slot); | 93 const char* slot_name = PK11_GetSlotName(slot); |
| 60 key_location.slot_name.assign(slot_name); | 94 key_location.slot_name.assign(slot_name); |
| 61 cache->Insert(std::string(reinterpret_cast<char*>(public_key_info.data), | 95 cache->Insert(std::string(reinterpret_cast<char*>(public_key_info.data), |
| 62 public_key_info.len), key_location); | 96 public_key_info.len), key_location); |
| 63 } | 97 } |
| 64 | 98 |
| 65 bool KeygenHandler::KeyLocation::Equals( | 99 } // namespace |
| 66 const net::KeygenHandler::KeyLocation& location) const { | |
| 67 return slot_name == location.slot_name; | |
| 68 } | |
| 69 | 100 |
| 70 // This function is largely copied from the Firefox's | 101 namespace mozilla_security_manager { |
| 71 // <keygen> implementation in security/manager/ssl/src/nsKeygenHandler.cpp | |
| 72 // FIXME(gauravsh): Do we need a copy of the Mozilla license here? | |
| 73 | 102 |
| 74 std::string KeygenHandler::GenKeyAndSignChallenge() { | 103 // This function is based on the nsKeygenFormProcessor::GetPublicKey function |
| 104 // in mozilla/security/manager/ssl/src/nsKeygenHandler.cpp. |
| 105 std::string GenKeyAndSignChallenge(int key_size_in_bits, |
| 106 const std::string& challenge, |
| 107 bool stores_key) { |
| 75 // Key pair generation mechanism - only RSA is supported at present. | 108 // Key pair generation mechanism - only RSA is supported at present. |
| 76 PRUint32 keyGenMechanism = CKM_RSA_PKCS_KEY_PAIR_GEN; // from nss/pkcs11t.h | 109 PRUint32 keyGenMechanism = CKM_RSA_PKCS_KEY_PAIR_GEN; // from nss/pkcs11t.h |
| 77 | 110 |
| 78 // Temporary structures used for generating the result | 111 // Temporary structures used for generating the result |
| 79 // in the right format. | 112 // in the right format. |
| 80 PK11SlotInfo *slot = NULL; | 113 PK11SlotInfo *slot = NULL; |
| 81 PK11RSAGenParams rsaKeyGenParams; // Keygen parameters. | 114 PK11RSAGenParams rsaKeyGenParams; // Keygen parameters. |
| 82 SECOidTag algTag; // used by SEC_DerSignData(). | 115 SECOidTag algTag; // used by SEC_DerSignData(). |
| 83 SECKEYPrivateKey *privateKey = NULL; | 116 SECKEYPrivateKey *privateKey = NULL; |
| 84 SECKEYPublicKey *publicKey = NULL; | 117 SECKEYPublicKey *publicKey = NULL; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 100 | 133 |
| 101 slot = base::GetDefaultNSSKeySlot(); | 134 slot = base::GetDefaultNSSKeySlot(); |
| 102 if (!slot) { | 135 if (!slot) { |
| 103 LOG(ERROR) << "Couldn't get Internal key slot!"; | 136 LOG(ERROR) << "Couldn't get Internal key slot!"; |
| 104 isSuccess = false; | 137 isSuccess = false; |
| 105 goto failure; | 138 goto failure; |
| 106 } | 139 } |
| 107 | 140 |
| 108 switch (keyGenMechanism) { | 141 switch (keyGenMechanism) { |
| 109 case CKM_RSA_PKCS_KEY_PAIR_GEN: | 142 case CKM_RSA_PKCS_KEY_PAIR_GEN: |
| 110 rsaKeyGenParams.keySizeInBits = key_size_in_bits_; | 143 rsaKeyGenParams.keySizeInBits = key_size_in_bits; |
| 111 rsaKeyGenParams.pe = DEFAULT_RSA_PUBLIC_EXPONENT; | 144 rsaKeyGenParams.pe = DEFAULT_RSA_KEYGEN_PE; |
| 112 keyGenParams = &rsaKeyGenParams; | 145 keyGenParams = &rsaKeyGenParams; |
| 113 | 146 |
| 114 algTag = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION; // from <nss/secoidt.h>. | 147 algTag = DEFAULT_RSA_KEYGEN_ALG; |
| 115 break; | 148 break; |
| 116 default: | 149 default: |
| 117 // TODO(gauravsh): If we ever support other mechanisms, | 150 // TODO(gauravsh): If we ever support other mechanisms, |
| 118 // this can be changed. | 151 // this can be changed. |
| 119 LOG(ERROR) << "Only RSA keygen mechanism is supported"; | 152 LOG(ERROR) << "Only RSA keygen mechanism is supported"; |
| 120 isSuccess = false; | 153 isSuccess = false; |
| 121 goto failure; | 154 goto failure; |
| 122 break; | |
| 123 } | 155 } |
| 124 | 156 |
| 125 // Need to make sure that the token was initialized. | 157 // Need to make sure that the token was initialized. |
| 126 // Assume a null password. | 158 // Assume a null password. |
| 127 sec_rv = PK11_Authenticate(slot, PR_TRUE, NULL); | 159 sec_rv = PK11_Authenticate(slot, PR_TRUE, NULL); |
| 128 if (SECSuccess != sec_rv) { | 160 if (SECSuccess != sec_rv) { |
| 129 LOG(ERROR) << "Couldn't initialze PK11 token!"; | 161 LOG(ERROR) << "Couldn't initialze PK11 token!"; |
| 130 isSuccess = false; | 162 isSuccess = false; |
| 131 goto failure; | 163 goto failure; |
| 132 } | 164 } |
| (...skipping 18 matching lines...) Expand all Loading... |
| 151 // Let's create that now. | 183 // Let's create that now. |
| 152 | 184 |
| 153 // Create a subject public key info from the public key. | 185 // Create a subject public key info from the public key. |
| 154 spkInfo = SECKEY_CreateSubjectPublicKeyInfo(publicKey); | 186 spkInfo = SECKEY_CreateSubjectPublicKeyInfo(publicKey); |
| 155 if (!spkInfo) { | 187 if (!spkInfo) { |
| 156 LOG(ERROR) << "Couldn't create SubjectPublicKeyInfo from public key"; | 188 LOG(ERROR) << "Couldn't create SubjectPublicKeyInfo from public key"; |
| 157 isSuccess = false; | 189 isSuccess = false; |
| 158 goto failure; | 190 goto failure; |
| 159 } | 191 } |
| 160 | 192 |
| 161 // Temporary work store used by NSS. | |
| 162 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); | 193 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
| 163 if (!arena) { | 194 if (!arena) { |
| 164 LOG(ERROR) << "PORT_NewArena: Couldn't allocate memory"; | 195 LOG(ERROR) << "PORT_NewArena: Couldn't allocate memory"; |
| 165 isSuccess = false; | 196 isSuccess = false; |
| 166 goto failure; | 197 goto failure; |
| 167 } | 198 } |
| 168 | 199 |
| 169 // DER encode the whole subjectPublicKeyInfo. | 200 // DER encode the whole subjectPublicKeyInfo. |
| 170 sec_rv = DER_Encode(arena, &spkiItem, CERTSubjectPublicKeyInfoTemplate, | 201 sec_rv = DER_Encode(arena, &spkiItem, CERTSubjectPublicKeyInfoTemplate, |
| 171 spkInfo); | 202 spkInfo); |
| 172 if (SECSuccess != sec_rv) { | 203 if (SECSuccess != sec_rv) { |
| 173 LOG(ERROR) << "Couldn't DER Encode subjectPublicKeyInfo"; | 204 LOG(ERROR) << "Couldn't DER Encode subjectPublicKeyInfo"; |
| 174 isSuccess = false; | 205 isSuccess = false; |
| 175 goto failure; | 206 goto failure; |
| 176 } | 207 } |
| 177 | 208 |
| 178 // Set up the PublicKeyAndChallenge data structure, then DER encode it. | 209 // Set up the PublicKeyAndChallenge data structure, then DER encode it. |
| 179 pkac.spki = spkiItem; | 210 pkac.spki = spkiItem; |
| 180 pkac.challenge.len = challenge_.length(); | 211 pkac.challenge.len = challenge.length(); |
| 181 pkac.challenge.data = (unsigned char *)strdup(challenge_.c_str()); | 212 pkac.challenge.data = (unsigned char *)strdup(challenge.c_str()); |
| 182 if (!pkac.challenge.data) { | 213 if (!pkac.challenge.data) { |
| 183 LOG(ERROR) << "Out of memory while making a copy of challenge data"; | 214 LOG(ERROR) << "Out of memory while making a copy of challenge data"; |
| 184 isSuccess = false; | 215 isSuccess = false; |
| 185 goto failure; | 216 goto failure; |
| 186 } | 217 } |
| 187 sec_rv = DER_Encode(arena, &pkacItem, CERTPublicKeyAndChallengeTemplate, | 218 sec_rv = DER_Encode(arena, &pkacItem, CERTPublicKeyAndChallengeTemplate, |
| 188 &pkac); | 219 &pkac); |
| 189 if (SECSuccess != sec_rv) { | 220 if (SECSuccess != sec_rv) { |
| 190 LOG(ERROR) << "Couldn't DER Encode PublicKeyAndChallenge"; | 221 LOG(ERROR) << "Couldn't DER Encode PublicKeyAndChallenge"; |
| 191 isSuccess = false; | 222 isSuccess = false; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 216 if (!isSuccess) { | 247 if (!isSuccess) { |
| 217 LOG(ERROR) << "SSL Keygen failed!"; | 248 LOG(ERROR) << "SSL Keygen failed!"; |
| 218 } else { | 249 } else { |
| 219 LOG(INFO) << "SSL Keygen succeeded!"; | 250 LOG(INFO) << "SSL Keygen succeeded!"; |
| 220 } | 251 } |
| 221 | 252 |
| 222 // Do cleanups | 253 // Do cleanups |
| 223 if (privateKey) { | 254 if (privateKey) { |
| 224 // On successful keygen we need to keep the private key, of course, | 255 // On successful keygen we need to keep the private key, of course, |
| 225 // or we won't be able to use the client certificate. | 256 // or we won't be able to use the client certificate. |
| 226 if (!isSuccess || !stores_key_) { | 257 if (!isSuccess || !stores_key) { |
| 227 PK11_DestroyTokenObject(privateKey->pkcs11Slot, privateKey->pkcs11ID); | 258 PK11_DestroyTokenObject(privateKey->pkcs11Slot, privateKey->pkcs11ID); |
| 228 } | 259 } |
| 229 SECKEY_DestroyPrivateKey(privateKey); | 260 SECKEY_DestroyPrivateKey(privateKey); |
| 230 } | 261 } |
| 231 | 262 |
| 232 if (publicKey) { | 263 if (publicKey) { |
| 233 if (!isSuccess || !stores_key_) { | 264 if (!isSuccess || !stores_key) { |
| 234 PK11_DestroyTokenObject(publicKey->pkcs11Slot, publicKey->pkcs11ID); | 265 PK11_DestroyTokenObject(publicKey->pkcs11Slot, publicKey->pkcs11ID); |
| 235 } | 266 } |
| 236 SECKEY_DestroyPublicKey(publicKey); | 267 SECKEY_DestroyPublicKey(publicKey); |
| 237 } | 268 } |
| 238 if (spkInfo) { | 269 if (spkInfo) { |
| 239 SECKEY_DestroySubjectPublicKeyInfo(spkInfo); | 270 SECKEY_DestroySubjectPublicKeyInfo(spkInfo); |
| 240 } | 271 } |
| 241 if (arena) { | 272 if (arena) { |
| 242 PORT_FreeArena(arena, PR_TRUE); | 273 PORT_FreeArena(arena, PR_TRUE); |
| 243 } | 274 } |
| 244 if (slot != NULL) { | 275 if (slot != NULL) { |
| 245 PK11_FreeSlot(slot); | 276 PK11_FreeSlot(slot); |
| 246 } | 277 } |
| 247 if (pkac.challenge.data) { | 278 if (pkac.challenge.data) { |
| 248 free(pkac.challenge.data); | 279 free(pkac.challenge.data); |
| 249 } | 280 } |
| 250 | 281 |
| 251 return (isSuccess ? result_blob : std::string()); | 282 return (isSuccess ? result_blob : std::string()); |
| 252 } | 283 } |
| 253 | 284 |
| 254 } // namespace net | 285 } // namespace mozilla_security_manager |
| OLD | NEW |