Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 5 | |
michael@0 | 6 | #include "nsNSSCertificate.h" |
michael@0 | 7 | |
michael@0 | 8 | #include "prmem.h" |
michael@0 | 9 | #include "prerror.h" |
michael@0 | 10 | #include "prprf.h" |
michael@0 | 11 | #include "CertVerifier.h" |
michael@0 | 12 | #include "ExtendedValidation.h" |
michael@0 | 13 | #include "pkix/pkixtypes.h" |
michael@0 | 14 | #include "nsNSSComponent.h" // for PIPNSS string bundle calls. |
michael@0 | 15 | #include "nsNSSCleaner.h" |
michael@0 | 16 | #include "nsCOMPtr.h" |
michael@0 | 17 | #include "nsIMutableArray.h" |
michael@0 | 18 | #include "nsNSSCertValidity.h" |
michael@0 | 19 | #include "nsPKCS12Blob.h" |
michael@0 | 20 | #include "nsPK11TokenDB.h" |
michael@0 | 21 | #include "nsIX509Cert.h" |
michael@0 | 22 | #include "nsIX509Cert3.h" |
michael@0 | 23 | #include "nsISMimeCert.h" |
michael@0 | 24 | #include "nsNSSASN1Object.h" |
michael@0 | 25 | #include "nsString.h" |
michael@0 | 26 | #include "nsXPIDLString.h" |
michael@0 | 27 | #include "nsReadableUtils.h" |
michael@0 | 28 | #include "nsIURI.h" |
michael@0 | 29 | #include "nsCRT.h" |
michael@0 | 30 | #include "nsUsageArrayHelper.h" |
michael@0 | 31 | #include "nsICertificateDialogs.h" |
michael@0 | 32 | #include "nsNSSCertHelper.h" |
michael@0 | 33 | #include "nsISupportsPrimitives.h" |
michael@0 | 34 | #include "nsUnicharUtils.h" |
michael@0 | 35 | #include "nsThreadUtils.h" |
michael@0 | 36 | #include "nsCertVerificationThread.h" |
michael@0 | 37 | #include "nsIObjectOutputStream.h" |
michael@0 | 38 | #include "nsIObjectInputStream.h" |
michael@0 | 39 | #include "nsIProgrammingLanguage.h" |
michael@0 | 40 | #include "nsXULAppAPI.h" |
michael@0 | 41 | #include "ScopedNSSTypes.h" |
michael@0 | 42 | #include "nsProxyRelease.h" |
michael@0 | 43 | #include "mozilla/Base64.h" |
michael@0 | 44 | |
michael@0 | 45 | #include "nspr.h" |
michael@0 | 46 | #include "certdb.h" |
michael@0 | 47 | #include "secerr.h" |
michael@0 | 48 | #include "nssb64.h" |
michael@0 | 49 | #include "secasn1.h" |
michael@0 | 50 | #include "secder.h" |
michael@0 | 51 | #include "ssl.h" |
michael@0 | 52 | #include "ocsp.h" |
michael@0 | 53 | #include "plbase64.h" |
michael@0 | 54 | |
michael@0 | 55 | using namespace mozilla; |
michael@0 | 56 | using namespace mozilla::psm; |
michael@0 | 57 | |
michael@0 | 58 | #ifdef PR_LOGGING |
michael@0 | 59 | extern PRLogModuleInfo* gPIPNSSLog; |
michael@0 | 60 | #endif |
michael@0 | 61 | |
michael@0 | 62 | NSSCleanupAutoPtrClass_WithParam(PLArenaPool, PORT_FreeArena, FalseParam, false) |
michael@0 | 63 | |
michael@0 | 64 | // This is being stored in an uint32_t that can otherwise |
michael@0 | 65 | // only take values from nsIX509Cert's list of cert types. |
michael@0 | 66 | // As nsIX509Cert is frozen, we choose a value not contained |
michael@0 | 67 | // in the list to mean not yet initialized. |
michael@0 | 68 | #define CERT_TYPE_NOT_YET_INITIALIZED (1 << 30) |
michael@0 | 69 | |
michael@0 | 70 | NS_IMPL_ISUPPORTS(nsNSSCertificate, |
michael@0 | 71 | nsIX509Cert, |
michael@0 | 72 | nsIX509Cert2, |
michael@0 | 73 | nsIX509Cert3, |
michael@0 | 74 | nsIIdentityInfo, |
michael@0 | 75 | nsISMimeCert, |
michael@0 | 76 | nsISerializable, |
michael@0 | 77 | nsIClassInfo) |
michael@0 | 78 | |
michael@0 | 79 | /*static*/ nsNSSCertificate* |
michael@0 | 80 | nsNSSCertificate::Create(CERTCertificate* cert, SECOidTag* evOidPolicy) |
michael@0 | 81 | { |
michael@0 | 82 | if (GeckoProcessType_Default != XRE_GetProcessType()) { |
michael@0 | 83 | NS_ERROR("Trying to initialize nsNSSCertificate in a non-chrome process!"); |
michael@0 | 84 | return nullptr; |
michael@0 | 85 | } |
michael@0 | 86 | if (cert) |
michael@0 | 87 | return new nsNSSCertificate(cert, evOidPolicy); |
michael@0 | 88 | else |
michael@0 | 89 | return new nsNSSCertificate(); |
michael@0 | 90 | } |
michael@0 | 91 | |
michael@0 | 92 | nsNSSCertificate* |
michael@0 | 93 | nsNSSCertificate::ConstructFromDER(char* certDER, int derLen) |
michael@0 | 94 | { |
michael@0 | 95 | // On non-chrome process prevent instantiation |
michael@0 | 96 | if (GeckoProcessType_Default != XRE_GetProcessType()) |
michael@0 | 97 | return nullptr; |
michael@0 | 98 | |
michael@0 | 99 | nsNSSCertificate* newObject = nsNSSCertificate::Create(); |
michael@0 | 100 | if (newObject && !newObject->InitFromDER(certDER, derLen)) { |
michael@0 | 101 | delete newObject; |
michael@0 | 102 | newObject = nullptr; |
michael@0 | 103 | } |
michael@0 | 104 | |
michael@0 | 105 | return newObject; |
michael@0 | 106 | } |
michael@0 | 107 | |
michael@0 | 108 | bool |
michael@0 | 109 | nsNSSCertificate::InitFromDER(char* certDER, int derLen) |
michael@0 | 110 | { |
michael@0 | 111 | nsNSSShutDownPreventionLock locker; |
michael@0 | 112 | if (isAlreadyShutDown()) |
michael@0 | 113 | return false; |
michael@0 | 114 | |
michael@0 | 115 | if (!certDER || !derLen) |
michael@0 | 116 | return false; |
michael@0 | 117 | |
michael@0 | 118 | CERTCertificate* aCert = CERT_DecodeCertFromPackage(certDER, derLen); |
michael@0 | 119 | |
michael@0 | 120 | if (!aCert) |
michael@0 | 121 | return false; |
michael@0 | 122 | |
michael@0 | 123 | if (!aCert->dbhandle) |
michael@0 | 124 | { |
michael@0 | 125 | aCert->dbhandle = CERT_GetDefaultCertDB(); |
michael@0 | 126 | } |
michael@0 | 127 | |
michael@0 | 128 | mCert = aCert; |
michael@0 | 129 | return true; |
michael@0 | 130 | } |
michael@0 | 131 | |
michael@0 | 132 | nsNSSCertificate::nsNSSCertificate(CERTCertificate* cert, |
michael@0 | 133 | SECOidTag* evOidPolicy) |
michael@0 | 134 | : mCert(nullptr) |
michael@0 | 135 | , mPermDelete(false) |
michael@0 | 136 | , mCertType(CERT_TYPE_NOT_YET_INITIALIZED) |
michael@0 | 137 | , mCachedEVStatus(ev_status_unknown) |
michael@0 | 138 | { |
michael@0 | 139 | #if defined(DEBUG) |
michael@0 | 140 | if (GeckoProcessType_Default != XRE_GetProcessType()) |
michael@0 | 141 | NS_ERROR("Trying to initialize nsNSSCertificate in a non-chrome process!"); |
michael@0 | 142 | #endif |
michael@0 | 143 | |
michael@0 | 144 | nsNSSShutDownPreventionLock locker; |
michael@0 | 145 | if (isAlreadyShutDown()) |
michael@0 | 146 | return; |
michael@0 | 147 | |
michael@0 | 148 | if (cert) { |
michael@0 | 149 | mCert = CERT_DupCertificate(cert); |
michael@0 | 150 | if (evOidPolicy) { |
michael@0 | 151 | if (*evOidPolicy == SEC_OID_UNKNOWN) { |
michael@0 | 152 | mCachedEVStatus = ev_status_invalid; |
michael@0 | 153 | } |
michael@0 | 154 | else { |
michael@0 | 155 | mCachedEVStatus = ev_status_valid; |
michael@0 | 156 | } |
michael@0 | 157 | mCachedEVOidTag = *evOidPolicy; |
michael@0 | 158 | } |
michael@0 | 159 | } |
michael@0 | 160 | } |
michael@0 | 161 | |
michael@0 | 162 | nsNSSCertificate::nsNSSCertificate() : |
michael@0 | 163 | mCert(nullptr), |
michael@0 | 164 | mPermDelete(false), |
michael@0 | 165 | mCertType(CERT_TYPE_NOT_YET_INITIALIZED), |
michael@0 | 166 | mCachedEVStatus(ev_status_unknown) |
michael@0 | 167 | { |
michael@0 | 168 | if (GeckoProcessType_Default != XRE_GetProcessType()) |
michael@0 | 169 | NS_ERROR("Trying to initialize nsNSSCertificate in a non-chrome process!"); |
michael@0 | 170 | } |
michael@0 | 171 | |
michael@0 | 172 | nsNSSCertificate::~nsNSSCertificate() |
michael@0 | 173 | { |
michael@0 | 174 | nsNSSShutDownPreventionLock locker; |
michael@0 | 175 | if (isAlreadyShutDown()) { |
michael@0 | 176 | return; |
michael@0 | 177 | } |
michael@0 | 178 | destructorSafeDestroyNSSReference(); |
michael@0 | 179 | shutdown(calledFromObject); |
michael@0 | 180 | } |
michael@0 | 181 | |
michael@0 | 182 | void nsNSSCertificate::virtualDestroyNSSReference() |
michael@0 | 183 | { |
michael@0 | 184 | destructorSafeDestroyNSSReference(); |
michael@0 | 185 | } |
michael@0 | 186 | |
michael@0 | 187 | void nsNSSCertificate::destructorSafeDestroyNSSReference() |
michael@0 | 188 | { |
michael@0 | 189 | if (mPermDelete) { |
michael@0 | 190 | if (mCertType == nsNSSCertificate::USER_CERT) { |
michael@0 | 191 | nsCOMPtr<nsIInterfaceRequestor> cxt = new PipUIContext(); |
michael@0 | 192 | PK11_DeleteTokenCertAndKey(mCert.get(), cxt); |
michael@0 | 193 | } else if (!PK11_IsReadOnly(mCert->slot)) { |
michael@0 | 194 | // If the list of built-ins does contain a non-removable |
michael@0 | 195 | // copy of this certificate, our call will not remove |
michael@0 | 196 | // the certificate permanently, but rather remove all trust. |
michael@0 | 197 | SEC_DeletePermCertificate(mCert.get()); |
michael@0 | 198 | } |
michael@0 | 199 | } |
michael@0 | 200 | |
michael@0 | 201 | mCert = nullptr; |
michael@0 | 202 | } |
michael@0 | 203 | |
michael@0 | 204 | nsresult |
michael@0 | 205 | nsNSSCertificate::GetCertType(uint32_t* aCertType) |
michael@0 | 206 | { |
michael@0 | 207 | if (mCertType == CERT_TYPE_NOT_YET_INITIALIZED) { |
michael@0 | 208 | // only determine cert type once and cache it |
michael@0 | 209 | mCertType = getCertType(mCert.get()); |
michael@0 | 210 | } |
michael@0 | 211 | *aCertType = mCertType; |
michael@0 | 212 | return NS_OK; |
michael@0 | 213 | } |
michael@0 | 214 | |
michael@0 | 215 | NS_IMETHODIMP |
michael@0 | 216 | nsNSSCertificate::GetIsSelfSigned(bool* aIsSelfSigned) |
michael@0 | 217 | { |
michael@0 | 218 | NS_ENSURE_ARG(aIsSelfSigned); |
michael@0 | 219 | |
michael@0 | 220 | nsNSSShutDownPreventionLock locker; |
michael@0 | 221 | if (isAlreadyShutDown()) |
michael@0 | 222 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 223 | |
michael@0 | 224 | *aIsSelfSigned = mCert->isRoot; |
michael@0 | 225 | return NS_OK; |
michael@0 | 226 | } |
michael@0 | 227 | |
michael@0 | 228 | nsresult |
michael@0 | 229 | nsNSSCertificate::MarkForPermDeletion() |
michael@0 | 230 | { |
michael@0 | 231 | nsNSSShutDownPreventionLock locker; |
michael@0 | 232 | if (isAlreadyShutDown()) |
michael@0 | 233 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 234 | |
michael@0 | 235 | // make sure user is logged in to the token |
michael@0 | 236 | nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext(); |
michael@0 | 237 | |
michael@0 | 238 | if (PK11_NeedLogin(mCert->slot) |
michael@0 | 239 | && !PK11_NeedUserInit(mCert->slot) |
michael@0 | 240 | && !PK11_IsInternal(mCert->slot)) |
michael@0 | 241 | { |
michael@0 | 242 | if (SECSuccess != PK11_Authenticate(mCert->slot, true, ctx)) |
michael@0 | 243 | { |
michael@0 | 244 | return NS_ERROR_FAILURE; |
michael@0 | 245 | } |
michael@0 | 246 | } |
michael@0 | 247 | |
michael@0 | 248 | mPermDelete = true; |
michael@0 | 249 | return NS_OK; |
michael@0 | 250 | } |
michael@0 | 251 | |
michael@0 | 252 | nsresult |
michael@0 | 253 | GetKeyUsagesString(CERTCertificate* cert, nsINSSComponent* nssComponent, |
michael@0 | 254 | nsString& text) |
michael@0 | 255 | { |
michael@0 | 256 | text.Truncate(); |
michael@0 | 257 | |
michael@0 | 258 | SECItem keyUsageItem; |
michael@0 | 259 | keyUsageItem.data = nullptr; |
michael@0 | 260 | |
michael@0 | 261 | SECStatus srv; |
michael@0 | 262 | |
michael@0 | 263 | // There is no extension, v1 or v2 certificate |
michael@0 | 264 | if (!cert->extensions) |
michael@0 | 265 | return NS_OK; |
michael@0 | 266 | |
michael@0 | 267 | |
michael@0 | 268 | srv = CERT_FindKeyUsageExtension(cert, &keyUsageItem); |
michael@0 | 269 | if (srv == SECFailure) { |
michael@0 | 270 | if (PORT_GetError () == SEC_ERROR_EXTENSION_NOT_FOUND) |
michael@0 | 271 | return NS_OK; |
michael@0 | 272 | else |
michael@0 | 273 | return NS_ERROR_FAILURE; |
michael@0 | 274 | } |
michael@0 | 275 | |
michael@0 | 276 | unsigned char keyUsage = keyUsageItem.data[0]; |
michael@0 | 277 | nsAutoString local; |
michael@0 | 278 | nsresult rv; |
michael@0 | 279 | const char16_t comma = ','; |
michael@0 | 280 | |
michael@0 | 281 | if (keyUsage & KU_DIGITAL_SIGNATURE) { |
michael@0 | 282 | rv = nssComponent->GetPIPNSSBundleString("CertDumpKUSign", local); |
michael@0 | 283 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 284 | if (!text.IsEmpty()) text.Append(comma); |
michael@0 | 285 | text.Append(local.get()); |
michael@0 | 286 | } |
michael@0 | 287 | } |
michael@0 | 288 | if (keyUsage & KU_NON_REPUDIATION) { |
michael@0 | 289 | rv = nssComponent->GetPIPNSSBundleString("CertDumpKUNonRep", local); |
michael@0 | 290 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 291 | if (!text.IsEmpty()) text.Append(comma); |
michael@0 | 292 | text.Append(local.get()); |
michael@0 | 293 | } |
michael@0 | 294 | } |
michael@0 | 295 | if (keyUsage & KU_KEY_ENCIPHERMENT) { |
michael@0 | 296 | rv = nssComponent->GetPIPNSSBundleString("CertDumpKUEnc", local); |
michael@0 | 297 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 298 | if (!text.IsEmpty()) text.Append(comma); |
michael@0 | 299 | text.Append(local.get()); |
michael@0 | 300 | } |
michael@0 | 301 | } |
michael@0 | 302 | if (keyUsage & KU_DATA_ENCIPHERMENT) { |
michael@0 | 303 | rv = nssComponent->GetPIPNSSBundleString("CertDumpKUDEnc", local); |
michael@0 | 304 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 305 | if (!text.IsEmpty()) text.Append(comma); |
michael@0 | 306 | text.Append(local.get()); |
michael@0 | 307 | } |
michael@0 | 308 | } |
michael@0 | 309 | if (keyUsage & KU_KEY_AGREEMENT) { |
michael@0 | 310 | rv = nssComponent->GetPIPNSSBundleString("CertDumpKUKA", local); |
michael@0 | 311 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 312 | if (!text.IsEmpty()) text.Append(comma); |
michael@0 | 313 | text.Append(local.get()); |
michael@0 | 314 | } |
michael@0 | 315 | } |
michael@0 | 316 | if (keyUsage & KU_KEY_CERT_SIGN) { |
michael@0 | 317 | rv = nssComponent->GetPIPNSSBundleString("CertDumpKUCertSign", local); |
michael@0 | 318 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 319 | if (!text.IsEmpty()) text.Append(comma); |
michael@0 | 320 | text.Append(local.get()); |
michael@0 | 321 | } |
michael@0 | 322 | } |
michael@0 | 323 | if (keyUsage & KU_CRL_SIGN) { |
michael@0 | 324 | rv = nssComponent->GetPIPNSSBundleString("CertDumpKUCRLSign", local); |
michael@0 | 325 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 326 | if (!text.IsEmpty()) text.Append(comma); |
michael@0 | 327 | text.Append(local.get()); |
michael@0 | 328 | } |
michael@0 | 329 | } |
michael@0 | 330 | |
michael@0 | 331 | PORT_Free (keyUsageItem.data); |
michael@0 | 332 | return NS_OK; |
michael@0 | 333 | } |
michael@0 | 334 | |
michael@0 | 335 | nsresult |
michael@0 | 336 | nsNSSCertificate::FormatUIStrings(const nsAutoString& nickname, |
michael@0 | 337 | nsAutoString& nickWithSerial, |
michael@0 | 338 | nsAutoString& details) |
michael@0 | 339 | { |
michael@0 | 340 | static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID); |
michael@0 | 341 | |
michael@0 | 342 | if (!NS_IsMainThread()) { |
michael@0 | 343 | NS_ERROR("nsNSSCertificate::FormatUIStrings called off the main thread"); |
michael@0 | 344 | return NS_ERROR_NOT_SAME_THREAD; |
michael@0 | 345 | } |
michael@0 | 346 | |
michael@0 | 347 | nsresult rv = NS_OK; |
michael@0 | 348 | |
michael@0 | 349 | nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv)); |
michael@0 | 350 | |
michael@0 | 351 | if (NS_FAILED(rv) || !nssComponent) { |
michael@0 | 352 | return NS_ERROR_FAILURE; |
michael@0 | 353 | } |
michael@0 | 354 | |
michael@0 | 355 | nsAutoString info; |
michael@0 | 356 | nsAutoString temp1; |
michael@0 | 357 | |
michael@0 | 358 | nickWithSerial.Append(nickname); |
michael@0 | 359 | |
michael@0 | 360 | if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoIssuedFor", info))) { |
michael@0 | 361 | details.Append(info); |
michael@0 | 362 | details.Append(char16_t(' ')); |
michael@0 | 363 | if (NS_SUCCEEDED(GetSubjectName(temp1)) && !temp1.IsEmpty()) { |
michael@0 | 364 | details.Append(temp1); |
michael@0 | 365 | } |
michael@0 | 366 | details.Append(char16_t('\n')); |
michael@0 | 367 | } |
michael@0 | 368 | |
michael@0 | 369 | if (NS_SUCCEEDED(GetSerialNumber(temp1)) && !temp1.IsEmpty()) { |
michael@0 | 370 | details.AppendLiteral(" "); |
michael@0 | 371 | if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertDumpSerialNo", info))) { |
michael@0 | 372 | details.Append(info); |
michael@0 | 373 | details.AppendLiteral(": "); |
michael@0 | 374 | } |
michael@0 | 375 | details.Append(temp1); |
michael@0 | 376 | |
michael@0 | 377 | nickWithSerial.AppendLiteral(" ["); |
michael@0 | 378 | nickWithSerial.Append(temp1); |
michael@0 | 379 | nickWithSerial.Append(char16_t(']')); |
michael@0 | 380 | |
michael@0 | 381 | details.Append(char16_t('\n')); |
michael@0 | 382 | } |
michael@0 | 383 | |
michael@0 | 384 | nsCOMPtr<nsIX509CertValidity> validity; |
michael@0 | 385 | rv = GetValidity(getter_AddRefs(validity)); |
michael@0 | 386 | if (NS_SUCCEEDED(rv) && validity) { |
michael@0 | 387 | details.AppendLiteral(" "); |
michael@0 | 388 | if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoValid", info))) { |
michael@0 | 389 | details.Append(info); |
michael@0 | 390 | } |
michael@0 | 391 | |
michael@0 | 392 | if (NS_SUCCEEDED(validity->GetNotBeforeLocalTime(temp1)) && !temp1.IsEmpty()) { |
michael@0 | 393 | details.Append(char16_t(' ')); |
michael@0 | 394 | if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoFrom", info))) { |
michael@0 | 395 | details.Append(info); |
michael@0 | 396 | details.Append(char16_t(' ')); |
michael@0 | 397 | } |
michael@0 | 398 | details.Append(temp1); |
michael@0 | 399 | } |
michael@0 | 400 | |
michael@0 | 401 | if (NS_SUCCEEDED(validity->GetNotAfterLocalTime(temp1)) && !temp1.IsEmpty()) { |
michael@0 | 402 | details.Append(char16_t(' ')); |
michael@0 | 403 | if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoTo", info))) { |
michael@0 | 404 | details.Append(info); |
michael@0 | 405 | details.Append(char16_t(' ')); |
michael@0 | 406 | } |
michael@0 | 407 | details.Append(temp1); |
michael@0 | 408 | } |
michael@0 | 409 | |
michael@0 | 410 | details.Append(char16_t('\n')); |
michael@0 | 411 | } |
michael@0 | 412 | |
michael@0 | 413 | if (NS_SUCCEEDED(GetKeyUsagesString(mCert.get(), nssComponent, temp1)) && |
michael@0 | 414 | !temp1.IsEmpty()) { |
michael@0 | 415 | details.AppendLiteral(" "); |
michael@0 | 416 | if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertDumpKeyUsage", info))) { |
michael@0 | 417 | details.Append(info); |
michael@0 | 418 | details.AppendLiteral(": "); |
michael@0 | 419 | } |
michael@0 | 420 | details.Append(temp1); |
michael@0 | 421 | details.Append(char16_t('\n')); |
michael@0 | 422 | } |
michael@0 | 423 | |
michael@0 | 424 | nsAutoString firstEmail; |
michael@0 | 425 | const char* aWalkAddr; |
michael@0 | 426 | for (aWalkAddr = CERT_GetFirstEmailAddress(mCert.get()) |
michael@0 | 427 | ; |
michael@0 | 428 | aWalkAddr |
michael@0 | 429 | ; |
michael@0 | 430 | aWalkAddr = CERT_GetNextEmailAddress(mCert.get(), aWalkAddr)) |
michael@0 | 431 | { |
michael@0 | 432 | NS_ConvertUTF8toUTF16 email(aWalkAddr); |
michael@0 | 433 | if (email.IsEmpty()) |
michael@0 | 434 | continue; |
michael@0 | 435 | |
michael@0 | 436 | if (firstEmail.IsEmpty()) { |
michael@0 | 437 | // If the first email address from the subject DN is also present |
michael@0 | 438 | // in the subjectAltName extension, GetEmailAddresses() will return |
michael@0 | 439 | // it twice (as received from NSS). Remember the first address so that |
michael@0 | 440 | // we can filter out duplicates later on. |
michael@0 | 441 | firstEmail = email; |
michael@0 | 442 | |
michael@0 | 443 | details.AppendLiteral(" "); |
michael@0 | 444 | if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoEmail", info))) { |
michael@0 | 445 | details.Append(info); |
michael@0 | 446 | details.AppendLiteral(": "); |
michael@0 | 447 | } |
michael@0 | 448 | details.Append(email); |
michael@0 | 449 | } |
michael@0 | 450 | else { |
michael@0 | 451 | // Append current address if it's different from the first one. |
michael@0 | 452 | if (!firstEmail.Equals(email)) { |
michael@0 | 453 | details.AppendLiteral(", "); |
michael@0 | 454 | details.Append(email); |
michael@0 | 455 | } |
michael@0 | 456 | } |
michael@0 | 457 | } |
michael@0 | 458 | |
michael@0 | 459 | if (!firstEmail.IsEmpty()) { |
michael@0 | 460 | // We got at least one email address, so we want a newline |
michael@0 | 461 | details.Append(char16_t('\n')); |
michael@0 | 462 | } |
michael@0 | 463 | |
michael@0 | 464 | if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoIssuedBy", info))) { |
michael@0 | 465 | details.Append(info); |
michael@0 | 466 | details.Append(char16_t(' ')); |
michael@0 | 467 | |
michael@0 | 468 | if (NS_SUCCEEDED(GetIssuerName(temp1)) && !temp1.IsEmpty()) { |
michael@0 | 469 | details.Append(temp1); |
michael@0 | 470 | } |
michael@0 | 471 | |
michael@0 | 472 | details.Append(char16_t('\n')); |
michael@0 | 473 | } |
michael@0 | 474 | |
michael@0 | 475 | if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoStoredIn", info))) { |
michael@0 | 476 | details.Append(info); |
michael@0 | 477 | details.Append(char16_t(' ')); |
michael@0 | 478 | |
michael@0 | 479 | if (NS_SUCCEEDED(GetTokenName(temp1)) && !temp1.IsEmpty()) { |
michael@0 | 480 | details.Append(temp1); |
michael@0 | 481 | } |
michael@0 | 482 | } |
michael@0 | 483 | |
michael@0 | 484 | // the above produces the following output: |
michael@0 | 485 | // |
michael@0 | 486 | // Issued to: $subjectName |
michael@0 | 487 | // Serial number: $serialNumber |
michael@0 | 488 | // Valid from: $starting_date to $expiration_date |
michael@0 | 489 | // Certificate Key usage: $usages |
michael@0 | 490 | // Email: $address(es) |
michael@0 | 491 | // Issued by: $issuerName |
michael@0 | 492 | // Stored in: $token |
michael@0 | 493 | |
michael@0 | 494 | return rv; |
michael@0 | 495 | } |
michael@0 | 496 | |
michael@0 | 497 | NS_IMETHODIMP |
michael@0 | 498 | nsNSSCertificate::GetDbKey(char** aDbKey) |
michael@0 | 499 | { |
michael@0 | 500 | nsNSSShutDownPreventionLock locker; |
michael@0 | 501 | if (isAlreadyShutDown()) |
michael@0 | 502 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 503 | |
michael@0 | 504 | SECItem key; |
michael@0 | 505 | |
michael@0 | 506 | NS_ENSURE_ARG(aDbKey); |
michael@0 | 507 | *aDbKey = nullptr; |
michael@0 | 508 | key.len = NS_NSS_LONG*4+mCert->serialNumber.len+mCert->derIssuer.len; |
michael@0 | 509 | key.data = (unsigned char*) nsMemory::Alloc(key.len); |
michael@0 | 510 | if (!key.data) |
michael@0 | 511 | return NS_ERROR_OUT_OF_MEMORY; |
michael@0 | 512 | NS_NSS_PUT_LONG(0,key.data); // later put moduleID |
michael@0 | 513 | NS_NSS_PUT_LONG(0,&key.data[NS_NSS_LONG]); // later put slotID |
michael@0 | 514 | NS_NSS_PUT_LONG(mCert->serialNumber.len,&key.data[NS_NSS_LONG*2]); |
michael@0 | 515 | NS_NSS_PUT_LONG(mCert->derIssuer.len,&key.data[NS_NSS_LONG*3]); |
michael@0 | 516 | memcpy(&key.data[NS_NSS_LONG*4], mCert->serialNumber.data, |
michael@0 | 517 | mCert->serialNumber.len); |
michael@0 | 518 | memcpy(&key.data[NS_NSS_LONG*4+mCert->serialNumber.len], |
michael@0 | 519 | mCert->derIssuer.data, mCert->derIssuer.len); |
michael@0 | 520 | |
michael@0 | 521 | *aDbKey = NSSBase64_EncodeItem(nullptr, nullptr, 0, &key); |
michael@0 | 522 | nsMemory::Free(key.data); // SECItem is a 'c' type without a destrutor |
michael@0 | 523 | return (*aDbKey) ? NS_OK : NS_ERROR_FAILURE; |
michael@0 | 524 | } |
michael@0 | 525 | |
michael@0 | 526 | NS_IMETHODIMP |
michael@0 | 527 | nsNSSCertificate::GetWindowTitle(char** aWindowTitle) |
michael@0 | 528 | { |
michael@0 | 529 | nsNSSShutDownPreventionLock locker; |
michael@0 | 530 | if (isAlreadyShutDown()) |
michael@0 | 531 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 532 | |
michael@0 | 533 | NS_ENSURE_ARG(aWindowTitle); |
michael@0 | 534 | if (mCert) { |
michael@0 | 535 | if (mCert->nickname) { |
michael@0 | 536 | *aWindowTitle = PL_strdup(mCert->nickname); |
michael@0 | 537 | } else { |
michael@0 | 538 | *aWindowTitle = CERT_GetCommonName(&mCert->subject); |
michael@0 | 539 | if (!*aWindowTitle) { |
michael@0 | 540 | if (mCert->subjectName) { |
michael@0 | 541 | *aWindowTitle = PL_strdup(mCert->subjectName); |
michael@0 | 542 | } else if (mCert->emailAddr) { |
michael@0 | 543 | *aWindowTitle = PL_strdup(mCert->emailAddr); |
michael@0 | 544 | } else { |
michael@0 | 545 | *aWindowTitle = PL_strdup(""); |
michael@0 | 546 | } |
michael@0 | 547 | } |
michael@0 | 548 | } |
michael@0 | 549 | } else { |
michael@0 | 550 | NS_ERROR("Somehow got nullptr for mCertificate in nsNSSCertificate."); |
michael@0 | 551 | *aWindowTitle = nullptr; |
michael@0 | 552 | } |
michael@0 | 553 | return NS_OK; |
michael@0 | 554 | } |
michael@0 | 555 | |
michael@0 | 556 | NS_IMETHODIMP |
michael@0 | 557 | nsNSSCertificate::GetNickname(nsAString& aNickname) |
michael@0 | 558 | { |
michael@0 | 559 | static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID); |
michael@0 | 560 | |
michael@0 | 561 | nsNSSShutDownPreventionLock locker; |
michael@0 | 562 | if (isAlreadyShutDown()) |
michael@0 | 563 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 564 | |
michael@0 | 565 | if (mCert->nickname) { |
michael@0 | 566 | CopyUTF8toUTF16(mCert->nickname, aNickname); |
michael@0 | 567 | } else { |
michael@0 | 568 | nsresult rv; |
michael@0 | 569 | nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv)); |
michael@0 | 570 | if (NS_FAILED(rv) || !nssComponent) { |
michael@0 | 571 | return NS_ERROR_FAILURE; |
michael@0 | 572 | } |
michael@0 | 573 | nssComponent->GetPIPNSSBundleString("CertNoNickname", aNickname); |
michael@0 | 574 | } |
michael@0 | 575 | return NS_OK; |
michael@0 | 576 | } |
michael@0 | 577 | |
michael@0 | 578 | NS_IMETHODIMP |
michael@0 | 579 | nsNSSCertificate::GetEmailAddress(nsAString& aEmailAddress) |
michael@0 | 580 | { |
michael@0 | 581 | static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID); |
michael@0 | 582 | |
michael@0 | 583 | nsNSSShutDownPreventionLock locker; |
michael@0 | 584 | if (isAlreadyShutDown()) |
michael@0 | 585 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 586 | |
michael@0 | 587 | if (mCert->emailAddr) { |
michael@0 | 588 | CopyUTF8toUTF16(mCert->emailAddr, aEmailAddress); |
michael@0 | 589 | } else { |
michael@0 | 590 | nsresult rv; |
michael@0 | 591 | nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv)); |
michael@0 | 592 | if (NS_FAILED(rv) || !nssComponent) { |
michael@0 | 593 | return NS_ERROR_FAILURE; |
michael@0 | 594 | } |
michael@0 | 595 | nssComponent->GetPIPNSSBundleString("CertNoEmailAddress", aEmailAddress); |
michael@0 | 596 | } |
michael@0 | 597 | return NS_OK; |
michael@0 | 598 | } |
michael@0 | 599 | |
michael@0 | 600 | NS_IMETHODIMP |
michael@0 | 601 | nsNSSCertificate::GetEmailAddresses(uint32_t* aLength, char16_t*** aAddresses) |
michael@0 | 602 | { |
michael@0 | 603 | nsNSSShutDownPreventionLock locker; |
michael@0 | 604 | if (isAlreadyShutDown()) |
michael@0 | 605 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 606 | |
michael@0 | 607 | NS_ENSURE_ARG(aLength); |
michael@0 | 608 | NS_ENSURE_ARG(aAddresses); |
michael@0 | 609 | |
michael@0 | 610 | *aLength = 0; |
michael@0 | 611 | |
michael@0 | 612 | const char* aAddr; |
michael@0 | 613 | for (aAddr = CERT_GetFirstEmailAddress(mCert.get()) |
michael@0 | 614 | ; |
michael@0 | 615 | aAddr |
michael@0 | 616 | ; |
michael@0 | 617 | aAddr = CERT_GetNextEmailAddress(mCert.get(), aAddr)) |
michael@0 | 618 | { |
michael@0 | 619 | ++(*aLength); |
michael@0 | 620 | } |
michael@0 | 621 | |
michael@0 | 622 | *aAddresses = (char16_t**) nsMemory::Alloc(sizeof(char16_t*) * (*aLength)); |
michael@0 | 623 | if (!*aAddresses) |
michael@0 | 624 | return NS_ERROR_OUT_OF_MEMORY; |
michael@0 | 625 | |
michael@0 | 626 | uint32_t iAddr; |
michael@0 | 627 | for (aAddr = CERT_GetFirstEmailAddress(mCert.get()), iAddr = 0 |
michael@0 | 628 | ; |
michael@0 | 629 | aAddr |
michael@0 | 630 | ; |
michael@0 | 631 | aAddr = CERT_GetNextEmailAddress(mCert.get(), aAddr), ++iAddr) |
michael@0 | 632 | { |
michael@0 | 633 | (*aAddresses)[iAddr] = ToNewUnicode(NS_ConvertUTF8toUTF16(aAddr)); |
michael@0 | 634 | } |
michael@0 | 635 | |
michael@0 | 636 | return NS_OK; |
michael@0 | 637 | } |
michael@0 | 638 | |
michael@0 | 639 | NS_IMETHODIMP |
michael@0 | 640 | nsNSSCertificate::ContainsEmailAddress(const nsAString& aEmailAddress, |
michael@0 | 641 | bool* result) |
michael@0 | 642 | { |
michael@0 | 643 | nsNSSShutDownPreventionLock locker; |
michael@0 | 644 | if (isAlreadyShutDown()) |
michael@0 | 645 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 646 | |
michael@0 | 647 | NS_ENSURE_ARG(result); |
michael@0 | 648 | *result = false; |
michael@0 | 649 | |
michael@0 | 650 | const char* aAddr = nullptr; |
michael@0 | 651 | for (aAddr = CERT_GetFirstEmailAddress(mCert.get()) |
michael@0 | 652 | ; |
michael@0 | 653 | aAddr |
michael@0 | 654 | ; |
michael@0 | 655 | aAddr = CERT_GetNextEmailAddress(mCert.get(), aAddr)) |
michael@0 | 656 | { |
michael@0 | 657 | NS_ConvertUTF8toUTF16 certAddr(aAddr); |
michael@0 | 658 | ToLowerCase(certAddr); |
michael@0 | 659 | |
michael@0 | 660 | nsAutoString testAddr(aEmailAddress); |
michael@0 | 661 | ToLowerCase(testAddr); |
michael@0 | 662 | |
michael@0 | 663 | if (certAddr == testAddr) |
michael@0 | 664 | { |
michael@0 | 665 | *result = true; |
michael@0 | 666 | break; |
michael@0 | 667 | } |
michael@0 | 668 | |
michael@0 | 669 | } |
michael@0 | 670 | |
michael@0 | 671 | return NS_OK; |
michael@0 | 672 | } |
michael@0 | 673 | |
michael@0 | 674 | NS_IMETHODIMP |
michael@0 | 675 | nsNSSCertificate::GetCommonName(nsAString& aCommonName) |
michael@0 | 676 | { |
michael@0 | 677 | nsNSSShutDownPreventionLock locker; |
michael@0 | 678 | if (isAlreadyShutDown()) |
michael@0 | 679 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 680 | |
michael@0 | 681 | aCommonName.Truncate(); |
michael@0 | 682 | if (mCert) { |
michael@0 | 683 | char* commonName = CERT_GetCommonName(&mCert->subject); |
michael@0 | 684 | if (commonName) { |
michael@0 | 685 | aCommonName = NS_ConvertUTF8toUTF16(commonName); |
michael@0 | 686 | PORT_Free(commonName); |
michael@0 | 687 | } |
michael@0 | 688 | } |
michael@0 | 689 | return NS_OK; |
michael@0 | 690 | } |
michael@0 | 691 | |
michael@0 | 692 | NS_IMETHODIMP |
michael@0 | 693 | nsNSSCertificate::GetOrganization(nsAString& aOrganization) |
michael@0 | 694 | { |
michael@0 | 695 | nsNSSShutDownPreventionLock locker; |
michael@0 | 696 | if (isAlreadyShutDown()) |
michael@0 | 697 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 698 | |
michael@0 | 699 | aOrganization.Truncate(); |
michael@0 | 700 | if (mCert) { |
michael@0 | 701 | char* organization = CERT_GetOrgName(&mCert->subject); |
michael@0 | 702 | if (organization) { |
michael@0 | 703 | aOrganization = NS_ConvertUTF8toUTF16(organization); |
michael@0 | 704 | PORT_Free(organization); |
michael@0 | 705 | } |
michael@0 | 706 | } |
michael@0 | 707 | return NS_OK; |
michael@0 | 708 | } |
michael@0 | 709 | |
michael@0 | 710 | NS_IMETHODIMP |
michael@0 | 711 | nsNSSCertificate::GetIssuerCommonName(nsAString& aCommonName) |
michael@0 | 712 | { |
michael@0 | 713 | nsNSSShutDownPreventionLock locker; |
michael@0 | 714 | if (isAlreadyShutDown()) |
michael@0 | 715 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 716 | |
michael@0 | 717 | aCommonName.Truncate(); |
michael@0 | 718 | if (mCert) { |
michael@0 | 719 | char* commonName = CERT_GetCommonName(&mCert->issuer); |
michael@0 | 720 | if (commonName) { |
michael@0 | 721 | aCommonName = NS_ConvertUTF8toUTF16(commonName); |
michael@0 | 722 | PORT_Free(commonName); |
michael@0 | 723 | } |
michael@0 | 724 | } |
michael@0 | 725 | return NS_OK; |
michael@0 | 726 | } |
michael@0 | 727 | |
michael@0 | 728 | NS_IMETHODIMP |
michael@0 | 729 | nsNSSCertificate::GetIssuerOrganization(nsAString& aOrganization) |
michael@0 | 730 | { |
michael@0 | 731 | nsNSSShutDownPreventionLock locker; |
michael@0 | 732 | if (isAlreadyShutDown()) |
michael@0 | 733 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 734 | |
michael@0 | 735 | aOrganization.Truncate(); |
michael@0 | 736 | if (mCert) { |
michael@0 | 737 | char* organization = CERT_GetOrgName(&mCert->issuer); |
michael@0 | 738 | if (organization) { |
michael@0 | 739 | aOrganization = NS_ConvertUTF8toUTF16(organization); |
michael@0 | 740 | PORT_Free(organization); |
michael@0 | 741 | } else { |
michael@0 | 742 | return GetIssuerCommonName(aOrganization); |
michael@0 | 743 | } |
michael@0 | 744 | } |
michael@0 | 745 | return NS_OK; |
michael@0 | 746 | } |
michael@0 | 747 | |
michael@0 | 748 | NS_IMETHODIMP |
michael@0 | 749 | nsNSSCertificate::GetIssuerOrganizationUnit(nsAString& aOrganizationUnit) |
michael@0 | 750 | { |
michael@0 | 751 | nsNSSShutDownPreventionLock locker; |
michael@0 | 752 | if (isAlreadyShutDown()) |
michael@0 | 753 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 754 | |
michael@0 | 755 | aOrganizationUnit.Truncate(); |
michael@0 | 756 | if (mCert) { |
michael@0 | 757 | char* organizationUnit = CERT_GetOrgUnitName(&mCert->issuer); |
michael@0 | 758 | if (organizationUnit) { |
michael@0 | 759 | aOrganizationUnit = NS_ConvertUTF8toUTF16(organizationUnit); |
michael@0 | 760 | PORT_Free(organizationUnit); |
michael@0 | 761 | } |
michael@0 | 762 | } |
michael@0 | 763 | return NS_OK; |
michael@0 | 764 | } |
michael@0 | 765 | |
michael@0 | 766 | NS_IMETHODIMP |
michael@0 | 767 | nsNSSCertificate::GetIssuer(nsIX509Cert** aIssuer) |
michael@0 | 768 | { |
michael@0 | 769 | nsNSSShutDownPreventionLock locker; |
michael@0 | 770 | if (isAlreadyShutDown()) |
michael@0 | 771 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 772 | |
michael@0 | 773 | NS_ENSURE_ARG(aIssuer); |
michael@0 | 774 | *aIssuer = nullptr; |
michael@0 | 775 | |
michael@0 | 776 | nsCOMPtr<nsIArray> chain; |
michael@0 | 777 | nsresult rv; |
michael@0 | 778 | rv = GetChain(getter_AddRefs(chain)); |
michael@0 | 779 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 780 | uint32_t length; |
michael@0 | 781 | if (!chain || NS_FAILED(chain->GetLength(&length)) || length == 0) { |
michael@0 | 782 | return NS_ERROR_UNEXPECTED; |
michael@0 | 783 | } |
michael@0 | 784 | if (length == 1) { // No known issuer |
michael@0 | 785 | return NS_OK; |
michael@0 | 786 | } |
michael@0 | 787 | nsCOMPtr<nsIX509Cert> cert; |
michael@0 | 788 | chain->QueryElementAt(1, NS_GET_IID(nsIX509Cert), getter_AddRefs(cert)); |
michael@0 | 789 | if (!cert) { |
michael@0 | 790 | return NS_ERROR_UNEXPECTED; |
michael@0 | 791 | } |
michael@0 | 792 | *aIssuer = cert; |
michael@0 | 793 | NS_ADDREF(*aIssuer); |
michael@0 | 794 | return NS_OK; |
michael@0 | 795 | } |
michael@0 | 796 | |
michael@0 | 797 | NS_IMETHODIMP |
michael@0 | 798 | nsNSSCertificate::GetOrganizationalUnit(nsAString& aOrganizationalUnit) |
michael@0 | 799 | { |
michael@0 | 800 | nsNSSShutDownPreventionLock locker; |
michael@0 | 801 | if (isAlreadyShutDown()) |
michael@0 | 802 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 803 | |
michael@0 | 804 | aOrganizationalUnit.Truncate(); |
michael@0 | 805 | if (mCert) { |
michael@0 | 806 | char* orgunit = CERT_GetOrgUnitName(&mCert->subject); |
michael@0 | 807 | if (orgunit) { |
michael@0 | 808 | aOrganizationalUnit = NS_ConvertUTF8toUTF16(orgunit); |
michael@0 | 809 | PORT_Free(orgunit); |
michael@0 | 810 | } |
michael@0 | 811 | } |
michael@0 | 812 | return NS_OK; |
michael@0 | 813 | } |
michael@0 | 814 | |
michael@0 | 815 | NS_IMETHODIMP |
michael@0 | 816 | nsNSSCertificate::GetChain(nsIArray** _rvChain) |
michael@0 | 817 | { |
michael@0 | 818 | nsNSSShutDownPreventionLock locker; |
michael@0 | 819 | if (isAlreadyShutDown()) |
michael@0 | 820 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 821 | |
michael@0 | 822 | NS_ENSURE_ARG(_rvChain); |
michael@0 | 823 | nsresult rv; |
michael@0 | 824 | PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Getting chain for \"%s\"\n", mCert->nickname)); |
michael@0 | 825 | |
michael@0 | 826 | ::mozilla::pkix::ScopedCERTCertList nssChain; |
michael@0 | 827 | RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier()); |
michael@0 | 828 | NS_ENSURE_TRUE(certVerifier, NS_ERROR_UNEXPECTED); |
michael@0 | 829 | |
michael@0 | 830 | // We want to test all usages, but we start with server because most of the |
michael@0 | 831 | // time Firefox users care about server certs. |
michael@0 | 832 | certVerifier->VerifyCert(mCert.get(), |
michael@0 | 833 | certificateUsageSSLServer, PR_Now(), |
michael@0 | 834 | nullptr, /*XXX fixme*/ |
michael@0 | 835 | nullptr, /* hostname */ |
michael@0 | 836 | CertVerifier::FLAG_LOCAL_ONLY, |
michael@0 | 837 | nullptr, /* stapledOCSPResponse */ |
michael@0 | 838 | &nssChain); |
michael@0 | 839 | // This is the whitelist of all non-SSLServer usages that are supported by |
michael@0 | 840 | // verifycert. |
michael@0 | 841 | const int otherUsagesToTest = certificateUsageSSLClient | |
michael@0 | 842 | certificateUsageSSLCA | |
michael@0 | 843 | certificateUsageEmailSigner | |
michael@0 | 844 | certificateUsageEmailRecipient | |
michael@0 | 845 | certificateUsageObjectSigner | |
michael@0 | 846 | certificateUsageStatusResponder; |
michael@0 | 847 | for (int usage = certificateUsageSSLClient; |
michael@0 | 848 | usage < certificateUsageAnyCA && !nssChain; |
michael@0 | 849 | usage = usage << 1) { |
michael@0 | 850 | if ((usage & otherUsagesToTest) == 0) { |
michael@0 | 851 | continue; |
michael@0 | 852 | } |
michael@0 | 853 | PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, |
michael@0 | 854 | ("pipnss: PKIX attempting chain(%d) for '%s'\n", |
michael@0 | 855 | usage, mCert->nickname)); |
michael@0 | 856 | certVerifier->VerifyCert(mCert.get(), |
michael@0 | 857 | usage, PR_Now(), |
michael@0 | 858 | nullptr, /*XXX fixme*/ |
michael@0 | 859 | nullptr, /*hostname*/ |
michael@0 | 860 | CertVerifier::FLAG_LOCAL_ONLY, |
michael@0 | 861 | nullptr, /* stapledOCSPResponse */ |
michael@0 | 862 | &nssChain); |
michael@0 | 863 | } |
michael@0 | 864 | |
michael@0 | 865 | if (!nssChain) { |
michael@0 | 866 | // There is not verified path for the chain, howeever we still want to |
michael@0 | 867 | // present to the user as much of a possible chain as possible, in the case |
michael@0 | 868 | // where there was a problem with the cert or the issuers. |
michael@0 | 869 | PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, |
michael@0 | 870 | ("pipnss: getchain :CertVerify failed to get chain for '%s'\n", |
michael@0 | 871 | mCert->nickname)); |
michael@0 | 872 | nssChain = CERT_GetCertChainFromCert(mCert.get(), PR_Now(), |
michael@0 | 873 | certUsageSSLClient); |
michael@0 | 874 | } |
michael@0 | 875 | |
michael@0 | 876 | if (!nssChain) { |
michael@0 | 877 | return NS_ERROR_FAILURE; |
michael@0 | 878 | } |
michael@0 | 879 | |
michael@0 | 880 | // enumerate the chain for scripting purposes |
michael@0 | 881 | nsCOMPtr<nsIMutableArray> array = |
michael@0 | 882 | do_CreateInstance(NS_ARRAY_CONTRACTID, &rv); |
michael@0 | 883 | if (NS_FAILED(rv)) { |
michael@0 | 884 | goto done; |
michael@0 | 885 | } |
michael@0 | 886 | CERTCertListNode* node; |
michael@0 | 887 | for (node = CERT_LIST_HEAD(nssChain.get()); |
michael@0 | 888 | !CERT_LIST_END(node, nssChain.get()); |
michael@0 | 889 | node = CERT_LIST_NEXT(node)) { |
michael@0 | 890 | PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, |
michael@0 | 891 | ("adding %s to chain\n", node->cert->nickname)); |
michael@0 | 892 | nsCOMPtr<nsIX509Cert> cert = nsNSSCertificate::Create(node->cert); |
michael@0 | 893 | array->AppendElement(cert, false); |
michael@0 | 894 | } |
michael@0 | 895 | *_rvChain = array; |
michael@0 | 896 | NS_IF_ADDREF(*_rvChain); |
michael@0 | 897 | rv = NS_OK; |
michael@0 | 898 | done: |
michael@0 | 899 | return rv; |
michael@0 | 900 | } |
michael@0 | 901 | |
michael@0 | 902 | NS_IMETHODIMP |
michael@0 | 903 | nsNSSCertificate::GetAllTokenNames(uint32_t* aLength, char16_t*** aTokenNames) |
michael@0 | 904 | { |
michael@0 | 905 | nsNSSShutDownPreventionLock locker; |
michael@0 | 906 | if (isAlreadyShutDown()) |
michael@0 | 907 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 908 | |
michael@0 | 909 | NS_ENSURE_ARG(aLength); |
michael@0 | 910 | NS_ENSURE_ARG(aTokenNames); |
michael@0 | 911 | *aLength = 0; |
michael@0 | 912 | *aTokenNames = nullptr; |
michael@0 | 913 | |
michael@0 | 914 | // Get the slots from NSS |
michael@0 | 915 | ScopedPK11SlotList slots; |
michael@0 | 916 | PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Getting slots for \"%s\"\n", mCert->nickname)); |
michael@0 | 917 | slots = PK11_GetAllSlotsForCert(mCert.get(), nullptr); |
michael@0 | 918 | if (!slots) { |
michael@0 | 919 | if (PORT_GetError() == SEC_ERROR_NO_TOKEN) |
michael@0 | 920 | return NS_OK; // List of slots is empty, return empty array |
michael@0 | 921 | else |
michael@0 | 922 | return NS_ERROR_FAILURE; |
michael@0 | 923 | } |
michael@0 | 924 | |
michael@0 | 925 | // read the token names from slots |
michael@0 | 926 | PK11SlotListElement* le; |
michael@0 | 927 | |
michael@0 | 928 | for (le = slots->head; le; le = le->next) { |
michael@0 | 929 | ++(*aLength); |
michael@0 | 930 | } |
michael@0 | 931 | |
michael@0 | 932 | *aTokenNames = (char16_t**) nsMemory::Alloc(sizeof(char16_t*) * (*aLength)); |
michael@0 | 933 | if (!*aTokenNames) { |
michael@0 | 934 | *aLength = 0; |
michael@0 | 935 | return NS_ERROR_OUT_OF_MEMORY; |
michael@0 | 936 | } |
michael@0 | 937 | |
michael@0 | 938 | uint32_t iToken; |
michael@0 | 939 | for (le = slots->head, iToken = 0; le; le = le->next, ++iToken) { |
michael@0 | 940 | char* token = PK11_GetTokenName(le->slot); |
michael@0 | 941 | (*aTokenNames)[iToken] = ToNewUnicode(NS_ConvertUTF8toUTF16(token)); |
michael@0 | 942 | if (!(*aTokenNames)[iToken]) { |
michael@0 | 943 | NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(iToken, *aTokenNames); |
michael@0 | 944 | *aLength = 0; |
michael@0 | 945 | *aTokenNames = nullptr; |
michael@0 | 946 | return NS_ERROR_OUT_OF_MEMORY; |
michael@0 | 947 | } |
michael@0 | 948 | } |
michael@0 | 949 | |
michael@0 | 950 | return NS_OK; |
michael@0 | 951 | } |
michael@0 | 952 | |
michael@0 | 953 | NS_IMETHODIMP |
michael@0 | 954 | nsNSSCertificate::GetSubjectName(nsAString& _subjectName) |
michael@0 | 955 | { |
michael@0 | 956 | nsNSSShutDownPreventionLock locker; |
michael@0 | 957 | if (isAlreadyShutDown()) |
michael@0 | 958 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 959 | |
michael@0 | 960 | _subjectName.Truncate(); |
michael@0 | 961 | if (mCert->subjectName) { |
michael@0 | 962 | _subjectName = NS_ConvertUTF8toUTF16(mCert->subjectName); |
michael@0 | 963 | return NS_OK; |
michael@0 | 964 | } |
michael@0 | 965 | return NS_ERROR_FAILURE; |
michael@0 | 966 | } |
michael@0 | 967 | |
michael@0 | 968 | NS_IMETHODIMP |
michael@0 | 969 | nsNSSCertificate::GetIssuerName(nsAString& _issuerName) |
michael@0 | 970 | { |
michael@0 | 971 | nsNSSShutDownPreventionLock locker; |
michael@0 | 972 | if (isAlreadyShutDown()) |
michael@0 | 973 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 974 | |
michael@0 | 975 | _issuerName.Truncate(); |
michael@0 | 976 | if (mCert->issuerName) { |
michael@0 | 977 | _issuerName = NS_ConvertUTF8toUTF16(mCert->issuerName); |
michael@0 | 978 | return NS_OK; |
michael@0 | 979 | } |
michael@0 | 980 | return NS_ERROR_FAILURE; |
michael@0 | 981 | } |
michael@0 | 982 | |
michael@0 | 983 | NS_IMETHODIMP |
michael@0 | 984 | nsNSSCertificate::GetSerialNumber(nsAString& _serialNumber) |
michael@0 | 985 | { |
michael@0 | 986 | nsNSSShutDownPreventionLock locker; |
michael@0 | 987 | if (isAlreadyShutDown()) |
michael@0 | 988 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 989 | |
michael@0 | 990 | _serialNumber.Truncate(); |
michael@0 | 991 | char* tmpstr = CERT_Hexify(&mCert->serialNumber, 1); |
michael@0 | 992 | if (tmpstr) { |
michael@0 | 993 | _serialNumber = NS_ConvertASCIItoUTF16(tmpstr); |
michael@0 | 994 | PORT_Free(tmpstr); |
michael@0 | 995 | return NS_OK; |
michael@0 | 996 | } |
michael@0 | 997 | return NS_ERROR_FAILURE; |
michael@0 | 998 | } |
michael@0 | 999 | |
michael@0 | 1000 | NS_IMETHODIMP |
michael@0 | 1001 | nsNSSCertificate::GetSha1Fingerprint(nsAString& _sha1Fingerprint) |
michael@0 | 1002 | { |
michael@0 | 1003 | nsNSSShutDownPreventionLock locker; |
michael@0 | 1004 | if (isAlreadyShutDown()) |
michael@0 | 1005 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 1006 | |
michael@0 | 1007 | _sha1Fingerprint.Truncate(); |
michael@0 | 1008 | unsigned char fingerprint[20]; |
michael@0 | 1009 | SECItem fpItem; |
michael@0 | 1010 | memset(fingerprint, 0, sizeof fingerprint); |
michael@0 | 1011 | PK11_HashBuf(SEC_OID_SHA1, fingerprint, |
michael@0 | 1012 | mCert->derCert.data, mCert->derCert.len); |
michael@0 | 1013 | fpItem.data = fingerprint; |
michael@0 | 1014 | fpItem.len = SHA1_LENGTH; |
michael@0 | 1015 | char* fpStr = CERT_Hexify(&fpItem, 1); |
michael@0 | 1016 | if (fpStr) { |
michael@0 | 1017 | _sha1Fingerprint = NS_ConvertASCIItoUTF16(fpStr); |
michael@0 | 1018 | PORT_Free(fpStr); |
michael@0 | 1019 | return NS_OK; |
michael@0 | 1020 | } |
michael@0 | 1021 | return NS_ERROR_FAILURE; |
michael@0 | 1022 | } |
michael@0 | 1023 | |
michael@0 | 1024 | NS_IMETHODIMP |
michael@0 | 1025 | nsNSSCertificate::GetMd5Fingerprint(nsAString& _md5Fingerprint) |
michael@0 | 1026 | { |
michael@0 | 1027 | nsNSSShutDownPreventionLock locker; |
michael@0 | 1028 | if (isAlreadyShutDown()) |
michael@0 | 1029 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 1030 | |
michael@0 | 1031 | _md5Fingerprint.Truncate(); |
michael@0 | 1032 | unsigned char fingerprint[20]; |
michael@0 | 1033 | SECItem fpItem; |
michael@0 | 1034 | memset(fingerprint, 0, sizeof fingerprint); |
michael@0 | 1035 | PK11_HashBuf(SEC_OID_MD5, fingerprint, |
michael@0 | 1036 | mCert->derCert.data, mCert->derCert.len); |
michael@0 | 1037 | fpItem.data = fingerprint; |
michael@0 | 1038 | fpItem.len = MD5_LENGTH; |
michael@0 | 1039 | char* fpStr = CERT_Hexify(&fpItem, 1); |
michael@0 | 1040 | if (fpStr) { |
michael@0 | 1041 | _md5Fingerprint = NS_ConvertASCIItoUTF16(fpStr); |
michael@0 | 1042 | PORT_Free(fpStr); |
michael@0 | 1043 | return NS_OK; |
michael@0 | 1044 | } |
michael@0 | 1045 | return NS_ERROR_FAILURE; |
michael@0 | 1046 | } |
michael@0 | 1047 | |
michael@0 | 1048 | NS_IMETHODIMP |
michael@0 | 1049 | nsNSSCertificate::GetTokenName(nsAString& aTokenName) |
michael@0 | 1050 | { |
michael@0 | 1051 | static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID); |
michael@0 | 1052 | |
michael@0 | 1053 | nsNSSShutDownPreventionLock locker; |
michael@0 | 1054 | if (isAlreadyShutDown()) |
michael@0 | 1055 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 1056 | |
michael@0 | 1057 | aTokenName.Truncate(); |
michael@0 | 1058 | if (mCert) { |
michael@0 | 1059 | // HACK alert |
michael@0 | 1060 | // When the trust of a builtin cert is modified, NSS copies it into the |
michael@0 | 1061 | // cert db. At this point, it is now "managed" by the user, and should |
michael@0 | 1062 | // not be listed with the builtins. However, in the collection code |
michael@0 | 1063 | // used by PK11_ListCerts, the cert is found in the temp db, where it |
michael@0 | 1064 | // has been loaded from the token. Though the trust is correct (grabbed |
michael@0 | 1065 | // from the cert db), the source is wrong. I believe this is a safe |
michael@0 | 1066 | // way to work around this. |
michael@0 | 1067 | if (mCert->slot) { |
michael@0 | 1068 | char* token = PK11_GetTokenName(mCert->slot); |
michael@0 | 1069 | if (token) { |
michael@0 | 1070 | aTokenName = NS_ConvertUTF8toUTF16(token); |
michael@0 | 1071 | } |
michael@0 | 1072 | } else { |
michael@0 | 1073 | nsresult rv; |
michael@0 | 1074 | nsAutoString tok; |
michael@0 | 1075 | nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv)); |
michael@0 | 1076 | if (NS_FAILED(rv)) return rv; |
michael@0 | 1077 | rv = nssComponent->GetPIPNSSBundleString("InternalToken", tok); |
michael@0 | 1078 | if (NS_SUCCEEDED(rv)) |
michael@0 | 1079 | aTokenName = tok; |
michael@0 | 1080 | } |
michael@0 | 1081 | } |
michael@0 | 1082 | return NS_OK; |
michael@0 | 1083 | } |
michael@0 | 1084 | |
michael@0 | 1085 | NS_IMETHODIMP |
michael@0 | 1086 | nsNSSCertificate::GetSha256SubjectPublicKeyInfoDigest(nsACString& aSha256SPKIDigest) |
michael@0 | 1087 | { |
michael@0 | 1088 | nsNSSShutDownPreventionLock locker; |
michael@0 | 1089 | if (isAlreadyShutDown()) { |
michael@0 | 1090 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 1091 | } |
michael@0 | 1092 | |
michael@0 | 1093 | aSha256SPKIDigest.Truncate(); |
michael@0 | 1094 | Digest digest; |
michael@0 | 1095 | nsresult rv = digest.DigestBuf(SEC_OID_SHA256, mCert->derPublicKey.data, |
michael@0 | 1096 | mCert->derPublicKey.len); |
michael@0 | 1097 | if (NS_WARN_IF(NS_FAILED(rv))) { |
michael@0 | 1098 | return rv; |
michael@0 | 1099 | } |
michael@0 | 1100 | rv = Base64Encode(nsDependentCSubstring( |
michael@0 | 1101 | reinterpret_cast<const char*> (digest.get().data), |
michael@0 | 1102 | digest.get().len), |
michael@0 | 1103 | aSha256SPKIDigest); |
michael@0 | 1104 | if (NS_WARN_IF(NS_FAILED(rv))) { |
michael@0 | 1105 | return rv; |
michael@0 | 1106 | } |
michael@0 | 1107 | return NS_OK; |
michael@0 | 1108 | } |
michael@0 | 1109 | |
michael@0 | 1110 | NS_IMETHODIMP |
michael@0 | 1111 | nsNSSCertificate::GetRawDER(uint32_t* aLength, uint8_t** aArray) |
michael@0 | 1112 | { |
michael@0 | 1113 | nsNSSShutDownPreventionLock locker; |
michael@0 | 1114 | if (isAlreadyShutDown()) |
michael@0 | 1115 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 1116 | |
michael@0 | 1117 | if (mCert) { |
michael@0 | 1118 | *aArray = (uint8_t*)nsMemory::Alloc(mCert->derCert.len); |
michael@0 | 1119 | if (*aArray) { |
michael@0 | 1120 | memcpy(*aArray, mCert->derCert.data, mCert->derCert.len); |
michael@0 | 1121 | *aLength = mCert->derCert.len; |
michael@0 | 1122 | return NS_OK; |
michael@0 | 1123 | } |
michael@0 | 1124 | } |
michael@0 | 1125 | *aLength = 0; |
michael@0 | 1126 | return NS_ERROR_FAILURE; |
michael@0 | 1127 | } |
michael@0 | 1128 | |
michael@0 | 1129 | NS_IMETHODIMP |
michael@0 | 1130 | nsNSSCertificate::ExportAsCMS(uint32_t chainMode, |
michael@0 | 1131 | uint32_t* aLength, uint8_t** aArray) |
michael@0 | 1132 | { |
michael@0 | 1133 | NS_ENSURE_ARG(aLength); |
michael@0 | 1134 | NS_ENSURE_ARG(aArray); |
michael@0 | 1135 | |
michael@0 | 1136 | nsNSSShutDownPreventionLock locker; |
michael@0 | 1137 | if (isAlreadyShutDown()) |
michael@0 | 1138 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 1139 | |
michael@0 | 1140 | if (!mCert) |
michael@0 | 1141 | return NS_ERROR_FAILURE; |
michael@0 | 1142 | |
michael@0 | 1143 | switch (chainMode) { |
michael@0 | 1144 | case nsIX509Cert3::CMS_CHAIN_MODE_CertOnly: |
michael@0 | 1145 | case nsIX509Cert3::CMS_CHAIN_MODE_CertChain: |
michael@0 | 1146 | case nsIX509Cert3::CMS_CHAIN_MODE_CertChainWithRoot: |
michael@0 | 1147 | break; |
michael@0 | 1148 | default: |
michael@0 | 1149 | return NS_ERROR_INVALID_ARG; |
michael@0 | 1150 | }; |
michael@0 | 1151 | |
michael@0 | 1152 | PLArenaPool* arena = PORT_NewArena(1024); |
michael@0 | 1153 | PLArenaPoolCleanerFalseParam arenaCleaner(arena); |
michael@0 | 1154 | if (!arena) { |
michael@0 | 1155 | PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, |
michael@0 | 1156 | ("nsNSSCertificate::ExportAsCMS - out of memory\n")); |
michael@0 | 1157 | return NS_ERROR_OUT_OF_MEMORY; |
michael@0 | 1158 | } |
michael@0 | 1159 | |
michael@0 | 1160 | ScopedNSSCMSMessage cmsg(NSS_CMSMessage_Create(nullptr)); |
michael@0 | 1161 | if (!cmsg) { |
michael@0 | 1162 | PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, |
michael@0 | 1163 | ("nsNSSCertificate::ExportAsCMS - can't create CMS message\n")); |
michael@0 | 1164 | return NS_ERROR_OUT_OF_MEMORY; |
michael@0 | 1165 | } |
michael@0 | 1166 | |
michael@0 | 1167 | // first, create SignedData with the certificate only (no chain) |
michael@0 | 1168 | ScopedNSSCMSSignedData sigd( |
michael@0 | 1169 | NSS_CMSSignedData_CreateCertsOnly(cmsg, mCert.get(), false)); |
michael@0 | 1170 | if (!sigd) { |
michael@0 | 1171 | PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, |
michael@0 | 1172 | ("nsNSSCertificate::ExportAsCMS - can't create SignedData\n")); |
michael@0 | 1173 | return NS_ERROR_FAILURE; |
michael@0 | 1174 | } |
michael@0 | 1175 | |
michael@0 | 1176 | // Calling NSS_CMSSignedData_CreateCertsOnly() will not allow us |
michael@0 | 1177 | // to specify the inclusion of the root, but CERT_CertChainFromCert() does. |
michael@0 | 1178 | // Since CERT_CertChainFromCert() also includes the certificate itself, |
michael@0 | 1179 | // we have to start at the issuing cert (to avoid duplicate certs |
michael@0 | 1180 | // in the SignedData). |
michael@0 | 1181 | if (chainMode == nsIX509Cert3::CMS_CHAIN_MODE_CertChain || |
michael@0 | 1182 | chainMode == nsIX509Cert3::CMS_CHAIN_MODE_CertChainWithRoot) { |
michael@0 | 1183 | ScopedCERTCertificate issuerCert( |
michael@0 | 1184 | CERT_FindCertIssuer(mCert.get(), PR_Now(), certUsageAnyCA)); |
michael@0 | 1185 | // the issuerCert of a self signed root is the cert itself, |
michael@0 | 1186 | // so make sure we're not adding duplicates, again |
michael@0 | 1187 | if (issuerCert && issuerCert != mCert.get()) { |
michael@0 | 1188 | bool includeRoot = |
michael@0 | 1189 | (chainMode == nsIX509Cert3::CMS_CHAIN_MODE_CertChainWithRoot); |
michael@0 | 1190 | ScopedCERTCertificateList certChain( |
michael@0 | 1191 | CERT_CertChainFromCert(issuerCert, certUsageAnyCA, includeRoot)); |
michael@0 | 1192 | if (certChain) { |
michael@0 | 1193 | if (NSS_CMSSignedData_AddCertList(sigd, certChain) == SECSuccess) { |
michael@0 | 1194 | certChain.forget(); |
michael@0 | 1195 | } |
michael@0 | 1196 | else { |
michael@0 | 1197 | PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, |
michael@0 | 1198 | ("nsNSSCertificate::ExportAsCMS - can't add chain\n")); |
michael@0 | 1199 | return NS_ERROR_FAILURE; |
michael@0 | 1200 | } |
michael@0 | 1201 | } |
michael@0 | 1202 | else { |
michael@0 | 1203 | // try to add the issuerCert, at least |
michael@0 | 1204 | if (NSS_CMSSignedData_AddCertificate(sigd, issuerCert) |
michael@0 | 1205 | == SECSuccess) { |
michael@0 | 1206 | issuerCert.forget(); |
michael@0 | 1207 | } |
michael@0 | 1208 | else { |
michael@0 | 1209 | PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, |
michael@0 | 1210 | ("nsNSSCertificate::ExportAsCMS - can't add issuer cert\n")); |
michael@0 | 1211 | return NS_ERROR_FAILURE; |
michael@0 | 1212 | } |
michael@0 | 1213 | } |
michael@0 | 1214 | } |
michael@0 | 1215 | } |
michael@0 | 1216 | |
michael@0 | 1217 | NSSCMSContentInfo* cinfo = NSS_CMSMessage_GetContentInfo(cmsg); |
michael@0 | 1218 | if (NSS_CMSContentInfo_SetContent_SignedData(cmsg, cinfo, sigd) |
michael@0 | 1219 | == SECSuccess) { |
michael@0 | 1220 | sigd.forget(); |
michael@0 | 1221 | } |
michael@0 | 1222 | else { |
michael@0 | 1223 | PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, |
michael@0 | 1224 | ("nsNSSCertificate::ExportAsCMS - can't attach SignedData\n")); |
michael@0 | 1225 | return NS_ERROR_FAILURE; |
michael@0 | 1226 | } |
michael@0 | 1227 | |
michael@0 | 1228 | SECItem certP7 = { siBuffer, nullptr, 0 }; |
michael@0 | 1229 | NSSCMSEncoderContext* ecx = NSS_CMSEncoder_Start(cmsg, nullptr, nullptr, |
michael@0 | 1230 | &certP7, arena, nullptr, |
michael@0 | 1231 | nullptr, nullptr, nullptr, |
michael@0 | 1232 | nullptr, nullptr); |
michael@0 | 1233 | if (!ecx) { |
michael@0 | 1234 | PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, |
michael@0 | 1235 | ("nsNSSCertificate::ExportAsCMS - can't create encoder context\n")); |
michael@0 | 1236 | return NS_ERROR_FAILURE; |
michael@0 | 1237 | } |
michael@0 | 1238 | |
michael@0 | 1239 | if (NSS_CMSEncoder_Finish(ecx) != SECSuccess) { |
michael@0 | 1240 | PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, |
michael@0 | 1241 | ("nsNSSCertificate::ExportAsCMS - failed to add encoded data\n")); |
michael@0 | 1242 | return NS_ERROR_FAILURE; |
michael@0 | 1243 | } |
michael@0 | 1244 | |
michael@0 | 1245 | *aArray = (uint8_t*)nsMemory::Alloc(certP7.len); |
michael@0 | 1246 | if (!*aArray) |
michael@0 | 1247 | return NS_ERROR_OUT_OF_MEMORY; |
michael@0 | 1248 | |
michael@0 | 1249 | memcpy(*aArray, certP7.data, certP7.len); |
michael@0 | 1250 | *aLength = certP7.len; |
michael@0 | 1251 | return NS_OK; |
michael@0 | 1252 | } |
michael@0 | 1253 | |
michael@0 | 1254 | CERTCertificate* |
michael@0 | 1255 | nsNSSCertificate::GetCert() |
michael@0 | 1256 | { |
michael@0 | 1257 | nsNSSShutDownPreventionLock locker; |
michael@0 | 1258 | if (isAlreadyShutDown()) |
michael@0 | 1259 | return nullptr; |
michael@0 | 1260 | |
michael@0 | 1261 | return (mCert) ? CERT_DupCertificate(mCert.get()) : nullptr; |
michael@0 | 1262 | } |
michael@0 | 1263 | |
michael@0 | 1264 | NS_IMETHODIMP |
michael@0 | 1265 | nsNSSCertificate::GetValidity(nsIX509CertValidity** aValidity) |
michael@0 | 1266 | { |
michael@0 | 1267 | nsNSSShutDownPreventionLock locker; |
michael@0 | 1268 | if (isAlreadyShutDown()) |
michael@0 | 1269 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 1270 | |
michael@0 | 1271 | NS_ENSURE_ARG(aValidity); |
michael@0 | 1272 | nsX509CertValidity* validity = new nsX509CertValidity(mCert.get()); |
michael@0 | 1273 | |
michael@0 | 1274 | NS_ADDREF(validity); |
michael@0 | 1275 | *aValidity = static_cast<nsIX509CertValidity*>(validity); |
michael@0 | 1276 | return NS_OK; |
michael@0 | 1277 | } |
michael@0 | 1278 | |
michael@0 | 1279 | NS_IMETHODIMP |
michael@0 | 1280 | nsNSSCertificate::GetUsagesArray(bool localOnly, |
michael@0 | 1281 | uint32_t* _verified, |
michael@0 | 1282 | uint32_t* _count, |
michael@0 | 1283 | char16_t*** _usages) |
michael@0 | 1284 | { |
michael@0 | 1285 | nsNSSShutDownPreventionLock locker; |
michael@0 | 1286 | if (isAlreadyShutDown()) |
michael@0 | 1287 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 1288 | |
michael@0 | 1289 | nsresult rv; |
michael@0 | 1290 | const int max_usages = 13; |
michael@0 | 1291 | char16_t* tmpUsages[max_usages]; |
michael@0 | 1292 | const char* suffix = ""; |
michael@0 | 1293 | uint32_t tmpCount; |
michael@0 | 1294 | nsUsageArrayHelper uah(mCert.get()); |
michael@0 | 1295 | rv = uah.GetUsagesArray(suffix, localOnly, max_usages, _verified, &tmpCount, |
michael@0 | 1296 | tmpUsages); |
michael@0 | 1297 | NS_ENSURE_SUCCESS(rv,rv); |
michael@0 | 1298 | if (tmpCount > 0) { |
michael@0 | 1299 | *_usages = (char16_t**) nsMemory::Alloc(sizeof(char16_t*) * tmpCount); |
michael@0 | 1300 | if (!*_usages) |
michael@0 | 1301 | return NS_ERROR_OUT_OF_MEMORY; |
michael@0 | 1302 | for (uint32_t i=0; i<tmpCount; i++) { |
michael@0 | 1303 | (*_usages)[i] = tmpUsages[i]; |
michael@0 | 1304 | } |
michael@0 | 1305 | *_count = tmpCount; |
michael@0 | 1306 | return NS_OK; |
michael@0 | 1307 | } |
michael@0 | 1308 | *_usages = (char16_t**) nsMemory::Alloc(sizeof(char16_t*)); |
michael@0 | 1309 | if (!*_usages) |
michael@0 | 1310 | return NS_ERROR_OUT_OF_MEMORY; |
michael@0 | 1311 | *_count = 0; |
michael@0 | 1312 | return NS_OK; |
michael@0 | 1313 | } |
michael@0 | 1314 | |
michael@0 | 1315 | NS_IMETHODIMP |
michael@0 | 1316 | nsNSSCertificate::RequestUsagesArrayAsync( |
michael@0 | 1317 | nsICertVerificationListener* aResultListener) |
michael@0 | 1318 | { |
michael@0 | 1319 | NS_ENSURE_TRUE(NS_IsMainThread(), NS_ERROR_NOT_SAME_THREAD); |
michael@0 | 1320 | |
michael@0 | 1321 | if (!aResultListener) |
michael@0 | 1322 | return NS_ERROR_FAILURE; |
michael@0 | 1323 | |
michael@0 | 1324 | nsCertVerificationJob* job = new nsCertVerificationJob; |
michael@0 | 1325 | |
michael@0 | 1326 | job->mCert = this; |
michael@0 | 1327 | job->mListener = |
michael@0 | 1328 | new nsMainThreadPtrHolder<nsICertVerificationListener>(aResultListener); |
michael@0 | 1329 | |
michael@0 | 1330 | nsresult rv = nsCertVerificationThread::addJob(job); |
michael@0 | 1331 | if (NS_FAILED(rv)) |
michael@0 | 1332 | delete job; |
michael@0 | 1333 | |
michael@0 | 1334 | return rv; |
michael@0 | 1335 | } |
michael@0 | 1336 | |
michael@0 | 1337 | NS_IMETHODIMP |
michael@0 | 1338 | nsNSSCertificate::GetUsagesString(bool localOnly, uint32_t* _verified, |
michael@0 | 1339 | nsAString& _usages) |
michael@0 | 1340 | { |
michael@0 | 1341 | nsNSSShutDownPreventionLock locker; |
michael@0 | 1342 | if (isAlreadyShutDown()) |
michael@0 | 1343 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 1344 | |
michael@0 | 1345 | nsresult rv; |
michael@0 | 1346 | const int max_usages = 13; |
michael@0 | 1347 | char16_t* tmpUsages[max_usages]; |
michael@0 | 1348 | const char* suffix = "_p"; |
michael@0 | 1349 | uint32_t tmpCount; |
michael@0 | 1350 | nsUsageArrayHelper uah(mCert.get()); |
michael@0 | 1351 | rv = uah.GetUsagesArray(suffix, localOnly, max_usages, _verified, &tmpCount, |
michael@0 | 1352 | tmpUsages); |
michael@0 | 1353 | NS_ENSURE_SUCCESS(rv,rv); |
michael@0 | 1354 | _usages.Truncate(); |
michael@0 | 1355 | for (uint32_t i=0; i<tmpCount; i++) { |
michael@0 | 1356 | if (i>0) _usages.AppendLiteral(","); |
michael@0 | 1357 | _usages.Append(tmpUsages[i]); |
michael@0 | 1358 | nsMemory::Free(tmpUsages[i]); |
michael@0 | 1359 | } |
michael@0 | 1360 | return NS_OK; |
michael@0 | 1361 | } |
michael@0 | 1362 | |
michael@0 | 1363 | #if defined(DEBUG_javi) || defined(DEBUG_jgmyers) |
michael@0 | 1364 | void |
michael@0 | 1365 | DumpASN1Object(nsIASN1Object* object, unsigned int level) |
michael@0 | 1366 | { |
michael@0 | 1367 | nsAutoString dispNameU, dispValU; |
michael@0 | 1368 | unsigned int i; |
michael@0 | 1369 | nsCOMPtr<nsIMutableArray> asn1Objects; |
michael@0 | 1370 | nsCOMPtr<nsISupports> isupports; |
michael@0 | 1371 | nsCOMPtr<nsIASN1Object> currObject; |
michael@0 | 1372 | bool processObjects; |
michael@0 | 1373 | uint32_t numObjects; |
michael@0 | 1374 | |
michael@0 | 1375 | for (i=0; i<level; i++) |
michael@0 | 1376 | printf (" "); |
michael@0 | 1377 | |
michael@0 | 1378 | object->GetDisplayName(dispNameU); |
michael@0 | 1379 | nsCOMPtr<nsIASN1Sequence> sequence(do_QueryInterface(object)); |
michael@0 | 1380 | if (sequence) { |
michael@0 | 1381 | printf ("%s ", NS_ConvertUTF16toUTF8(dispNameU).get()); |
michael@0 | 1382 | sequence->GetIsValidContainer(&processObjects); |
michael@0 | 1383 | if (processObjects) { |
michael@0 | 1384 | printf("\n"); |
michael@0 | 1385 | sequence->GetASN1Objects(getter_AddRefs(asn1Objects)); |
michael@0 | 1386 | asn1Objects->GetLength(&numObjects); |
michael@0 | 1387 | for (i=0; i<numObjects;i++) { |
michael@0 | 1388 | asn1Objects->QueryElementAt(i, NS_GET_IID(nsISupports), |
michael@0 | 1389 | getter_AddRefs(currObject)); |
michael@0 | 1390 | DumpASN1Object(currObject, level+1); |
michael@0 | 1391 | } |
michael@0 | 1392 | } else { |
michael@0 | 1393 | object->GetDisplayValue(dispValU); |
michael@0 | 1394 | printf("= %s\n", NS_ConvertUTF16toUTF8(dispValU).get()); |
michael@0 | 1395 | } |
michael@0 | 1396 | } else { |
michael@0 | 1397 | object->GetDisplayValue(dispValU); |
michael@0 | 1398 | printf("%s = %s\n",NS_ConvertUTF16toUTF8(dispNameU).get(), |
michael@0 | 1399 | NS_ConvertUTF16toUTF8(dispValU).get()); |
michael@0 | 1400 | } |
michael@0 | 1401 | } |
michael@0 | 1402 | #endif |
michael@0 | 1403 | |
michael@0 | 1404 | NS_IMETHODIMP |
michael@0 | 1405 | nsNSSCertificate::GetASN1Structure(nsIASN1Object** aASN1Structure) |
michael@0 | 1406 | { |
michael@0 | 1407 | nsNSSShutDownPreventionLock locker; |
michael@0 | 1408 | nsresult rv = NS_OK; |
michael@0 | 1409 | NS_ENSURE_ARG_POINTER(aASN1Structure); |
michael@0 | 1410 | // First create the recursive structure os ASN1Objects |
michael@0 | 1411 | // which tells us the layout of the cert. |
michael@0 | 1412 | rv = CreateASN1Struct(aASN1Structure); |
michael@0 | 1413 | if (NS_FAILED(rv)) { |
michael@0 | 1414 | return rv; |
michael@0 | 1415 | } |
michael@0 | 1416 | #ifdef DEBUG_javi |
michael@0 | 1417 | DumpASN1Object(*aASN1Structure, 0); |
michael@0 | 1418 | #endif |
michael@0 | 1419 | return rv; |
michael@0 | 1420 | } |
michael@0 | 1421 | |
michael@0 | 1422 | NS_IMETHODIMP |
michael@0 | 1423 | nsNSSCertificate::Equals(nsIX509Cert* other, bool* result) |
michael@0 | 1424 | { |
michael@0 | 1425 | nsNSSShutDownPreventionLock locker; |
michael@0 | 1426 | if (isAlreadyShutDown()) |
michael@0 | 1427 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 1428 | |
michael@0 | 1429 | NS_ENSURE_ARG(other); |
michael@0 | 1430 | NS_ENSURE_ARG(result); |
michael@0 | 1431 | |
michael@0 | 1432 | nsCOMPtr<nsIX509Cert2> other2 = do_QueryInterface(other); |
michael@0 | 1433 | if (!other2) |
michael@0 | 1434 | return NS_ERROR_FAILURE; |
michael@0 | 1435 | |
michael@0 | 1436 | ScopedCERTCertificate cert(other2->GetCert()); |
michael@0 | 1437 | *result = (mCert.get() == cert.get()); |
michael@0 | 1438 | return NS_OK; |
michael@0 | 1439 | } |
michael@0 | 1440 | |
michael@0 | 1441 | NS_IMETHODIMP |
michael@0 | 1442 | nsNSSCertificate::SaveSMimeProfile() |
michael@0 | 1443 | { |
michael@0 | 1444 | nsNSSShutDownPreventionLock locker; |
michael@0 | 1445 | if (isAlreadyShutDown()) |
michael@0 | 1446 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 1447 | |
michael@0 | 1448 | if (SECSuccess != CERT_SaveSMimeProfile(mCert.get(), nullptr, nullptr)) |
michael@0 | 1449 | return NS_ERROR_FAILURE; |
michael@0 | 1450 | else |
michael@0 | 1451 | return NS_OK; |
michael@0 | 1452 | } |
michael@0 | 1453 | |
michael@0 | 1454 | #ifndef MOZ_NO_EV_CERTS |
michael@0 | 1455 | |
michael@0 | 1456 | nsresult |
michael@0 | 1457 | nsNSSCertificate::hasValidEVOidTag(SECOidTag& resultOidTag, bool& validEV) |
michael@0 | 1458 | { |
michael@0 | 1459 | nsNSSShutDownPreventionLock locker; |
michael@0 | 1460 | if (isAlreadyShutDown()) |
michael@0 | 1461 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 1462 | |
michael@0 | 1463 | EnsureIdentityInfoLoaded(); |
michael@0 | 1464 | |
michael@0 | 1465 | RefPtr<mozilla::psm::SharedCertVerifier> |
michael@0 | 1466 | certVerifier(mozilla::psm::GetDefaultCertVerifier()); |
michael@0 | 1467 | NS_ENSURE_TRUE(certVerifier, NS_ERROR_UNEXPECTED); |
michael@0 | 1468 | |
michael@0 | 1469 | validEV = false; |
michael@0 | 1470 | resultOidTag = SEC_OID_UNKNOWN; |
michael@0 | 1471 | |
michael@0 | 1472 | uint32_t flags = mozilla::psm::CertVerifier::FLAG_LOCAL_ONLY | |
michael@0 | 1473 | mozilla::psm::CertVerifier::FLAG_MUST_BE_EV; |
michael@0 | 1474 | SECStatus rv = certVerifier->VerifyCert(mCert.get(), |
michael@0 | 1475 | certificateUsageSSLServer, PR_Now(), |
michael@0 | 1476 | nullptr /* XXX pinarg */, |
michael@0 | 1477 | nullptr /* hostname */, |
michael@0 | 1478 | flags, nullptr /* stapledOCSPResponse */ , nullptr, &resultOidTag); |
michael@0 | 1479 | |
michael@0 | 1480 | if (rv != SECSuccess) { |
michael@0 | 1481 | resultOidTag = SEC_OID_UNKNOWN; |
michael@0 | 1482 | } |
michael@0 | 1483 | if (resultOidTag != SEC_OID_UNKNOWN) { |
michael@0 | 1484 | validEV = true; |
michael@0 | 1485 | } |
michael@0 | 1486 | return NS_OK; |
michael@0 | 1487 | } |
michael@0 | 1488 | |
michael@0 | 1489 | nsresult |
michael@0 | 1490 | nsNSSCertificate::getValidEVOidTag(SECOidTag& resultOidTag, bool& validEV) |
michael@0 | 1491 | { |
michael@0 | 1492 | if (mCachedEVStatus != ev_status_unknown) { |
michael@0 | 1493 | validEV = (mCachedEVStatus == ev_status_valid); |
michael@0 | 1494 | if (validEV) { |
michael@0 | 1495 | resultOidTag = mCachedEVOidTag; |
michael@0 | 1496 | } |
michael@0 | 1497 | return NS_OK; |
michael@0 | 1498 | } |
michael@0 | 1499 | |
michael@0 | 1500 | nsresult rv = hasValidEVOidTag(resultOidTag, validEV); |
michael@0 | 1501 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 1502 | if (validEV) { |
michael@0 | 1503 | mCachedEVOidTag = resultOidTag; |
michael@0 | 1504 | } |
michael@0 | 1505 | mCachedEVStatus = validEV ? ev_status_valid : ev_status_invalid; |
michael@0 | 1506 | } |
michael@0 | 1507 | return rv; |
michael@0 | 1508 | } |
michael@0 | 1509 | |
michael@0 | 1510 | #endif // MOZ_NO_EV_CERTS |
michael@0 | 1511 | |
michael@0 | 1512 | NS_IMETHODIMP |
michael@0 | 1513 | nsNSSCertificate::GetIsExtendedValidation(bool* aIsEV) |
michael@0 | 1514 | { |
michael@0 | 1515 | #ifdef MOZ_NO_EV_CERTS |
michael@0 | 1516 | *aIsEV = false; |
michael@0 | 1517 | return NS_OK; |
michael@0 | 1518 | #else |
michael@0 | 1519 | nsNSSShutDownPreventionLock locker; |
michael@0 | 1520 | if (isAlreadyShutDown()) { |
michael@0 | 1521 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 1522 | } |
michael@0 | 1523 | |
michael@0 | 1524 | NS_ENSURE_ARG(aIsEV); |
michael@0 | 1525 | *aIsEV = false; |
michael@0 | 1526 | |
michael@0 | 1527 | if (mCachedEVStatus != ev_status_unknown) { |
michael@0 | 1528 | *aIsEV = (mCachedEVStatus == ev_status_valid); |
michael@0 | 1529 | return NS_OK; |
michael@0 | 1530 | } |
michael@0 | 1531 | |
michael@0 | 1532 | SECOidTag oid_tag; |
michael@0 | 1533 | return getValidEVOidTag(oid_tag, *aIsEV); |
michael@0 | 1534 | #endif |
michael@0 | 1535 | } |
michael@0 | 1536 | |
michael@0 | 1537 | NS_IMETHODIMP |
michael@0 | 1538 | nsNSSCertificate::GetValidEVPolicyOid(nsACString& outDottedOid) |
michael@0 | 1539 | { |
michael@0 | 1540 | outDottedOid.Truncate(); |
michael@0 | 1541 | |
michael@0 | 1542 | #ifndef MOZ_NO_EV_CERTS |
michael@0 | 1543 | nsNSSShutDownPreventionLock locker; |
michael@0 | 1544 | if (isAlreadyShutDown()) { |
michael@0 | 1545 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 1546 | } |
michael@0 | 1547 | |
michael@0 | 1548 | SECOidTag oid_tag; |
michael@0 | 1549 | bool valid; |
michael@0 | 1550 | nsresult rv = getValidEVOidTag(oid_tag, valid); |
michael@0 | 1551 | if (NS_FAILED(rv)) { |
michael@0 | 1552 | return rv; |
michael@0 | 1553 | } |
michael@0 | 1554 | |
michael@0 | 1555 | if (valid) { |
michael@0 | 1556 | SECOidData* oid_data = SECOID_FindOIDByTag(oid_tag); |
michael@0 | 1557 | if (!oid_data) { |
michael@0 | 1558 | return NS_ERROR_FAILURE; |
michael@0 | 1559 | } |
michael@0 | 1560 | |
michael@0 | 1561 | char* oid_str = CERT_GetOidString(&oid_data->oid); |
michael@0 | 1562 | if (!oid_str) { |
michael@0 | 1563 | return NS_ERROR_FAILURE; |
michael@0 | 1564 | } |
michael@0 | 1565 | |
michael@0 | 1566 | outDottedOid.Assign(oid_str); |
michael@0 | 1567 | PR_smprintf_free(oid_str); |
michael@0 | 1568 | } |
michael@0 | 1569 | #endif |
michael@0 | 1570 | |
michael@0 | 1571 | return NS_OK; |
michael@0 | 1572 | } |
michael@0 | 1573 | |
michael@0 | 1574 | NS_IMPL_ISUPPORTS(nsNSSCertList, nsIX509CertList) |
michael@0 | 1575 | |
michael@0 | 1576 | nsNSSCertList::nsNSSCertList(mozilla::pkix::ScopedCERTCertList& certList, |
michael@0 | 1577 | const nsNSSShutDownPreventionLock& proofOfLock) |
michael@0 | 1578 | { |
michael@0 | 1579 | if (certList) { |
michael@0 | 1580 | mCertList = certList.release(); |
michael@0 | 1581 | } else { |
michael@0 | 1582 | mCertList = CERT_NewCertList(); |
michael@0 | 1583 | } |
michael@0 | 1584 | } |
michael@0 | 1585 | |
michael@0 | 1586 | nsNSSCertList::nsNSSCertList() |
michael@0 | 1587 | { |
michael@0 | 1588 | mCertList = CERT_NewCertList(); |
michael@0 | 1589 | } |
michael@0 | 1590 | |
michael@0 | 1591 | nsNSSCertList::~nsNSSCertList() |
michael@0 | 1592 | { |
michael@0 | 1593 | nsNSSShutDownPreventionLock locker; |
michael@0 | 1594 | if (isAlreadyShutDown()) { |
michael@0 | 1595 | return; |
michael@0 | 1596 | } |
michael@0 | 1597 | destructorSafeDestroyNSSReference(); |
michael@0 | 1598 | shutdown(calledFromObject); |
michael@0 | 1599 | } |
michael@0 | 1600 | |
michael@0 | 1601 | void nsNSSCertList::virtualDestroyNSSReference() |
michael@0 | 1602 | { |
michael@0 | 1603 | destructorSafeDestroyNSSReference(); |
michael@0 | 1604 | } |
michael@0 | 1605 | |
michael@0 | 1606 | void nsNSSCertList::destructorSafeDestroyNSSReference() |
michael@0 | 1607 | { |
michael@0 | 1608 | if (mCertList) { |
michael@0 | 1609 | mCertList = nullptr; |
michael@0 | 1610 | } |
michael@0 | 1611 | } |
michael@0 | 1612 | |
michael@0 | 1613 | NS_IMETHODIMP |
michael@0 | 1614 | nsNSSCertList::AddCert(nsIX509Cert* aCert) |
michael@0 | 1615 | { |
michael@0 | 1616 | nsNSSShutDownPreventionLock locker; |
michael@0 | 1617 | if (isAlreadyShutDown()) { |
michael@0 | 1618 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 1619 | } |
michael@0 | 1620 | nsCOMPtr<nsIX509Cert2> nssCert = do_QueryInterface(aCert); |
michael@0 | 1621 | CERTCertificate* cert; |
michael@0 | 1622 | |
michael@0 | 1623 | cert = nssCert->GetCert(); |
michael@0 | 1624 | if (!cert) { |
michael@0 | 1625 | NS_ERROR("Somehow got nullptr for mCertificate in nsNSSCertificate."); |
michael@0 | 1626 | return NS_ERROR_FAILURE; |
michael@0 | 1627 | } |
michael@0 | 1628 | |
michael@0 | 1629 | if (!mCertList) { |
michael@0 | 1630 | NS_ERROR("Somehow got nullptr for mCertList in nsNSSCertList."); |
michael@0 | 1631 | return NS_ERROR_FAILURE; |
michael@0 | 1632 | } |
michael@0 | 1633 | // XXX: check return value! |
michael@0 | 1634 | CERT_AddCertToListTail(mCertList.get(), cert); |
michael@0 | 1635 | return NS_OK; |
michael@0 | 1636 | } |
michael@0 | 1637 | |
michael@0 | 1638 | NS_IMETHODIMP |
michael@0 | 1639 | nsNSSCertList::DeleteCert(nsIX509Cert* aCert) |
michael@0 | 1640 | { |
michael@0 | 1641 | nsNSSShutDownPreventionLock locker; |
michael@0 | 1642 | if (isAlreadyShutDown()) { |
michael@0 | 1643 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 1644 | } |
michael@0 | 1645 | nsCOMPtr<nsIX509Cert2> nssCert = do_QueryInterface(aCert); |
michael@0 | 1646 | CERTCertificate* cert = nssCert->GetCert(); |
michael@0 | 1647 | CERTCertListNode* node; |
michael@0 | 1648 | |
michael@0 | 1649 | if (!cert) { |
michael@0 | 1650 | NS_ERROR("Somehow got nullptr for mCertificate in nsNSSCertificate."); |
michael@0 | 1651 | return NS_ERROR_FAILURE; |
michael@0 | 1652 | } |
michael@0 | 1653 | |
michael@0 | 1654 | if (!mCertList) { |
michael@0 | 1655 | NS_ERROR("Somehow got nullptr for mCertList in nsNSSCertList."); |
michael@0 | 1656 | return NS_ERROR_FAILURE; |
michael@0 | 1657 | } |
michael@0 | 1658 | |
michael@0 | 1659 | for (node = CERT_LIST_HEAD(mCertList.get()); |
michael@0 | 1660 | !CERT_LIST_END(node, mCertList.get()); node = CERT_LIST_NEXT(node)) { |
michael@0 | 1661 | if (node->cert == cert) { |
michael@0 | 1662 | CERT_RemoveCertListNode(node); |
michael@0 | 1663 | return NS_OK; |
michael@0 | 1664 | } |
michael@0 | 1665 | } |
michael@0 | 1666 | return NS_OK; // XXX Should we fail if we couldn't find it? |
michael@0 | 1667 | } |
michael@0 | 1668 | |
michael@0 | 1669 | CERTCertList* |
michael@0 | 1670 | nsNSSCertList::DupCertList(CERTCertList* aCertList, |
michael@0 | 1671 | const nsNSSShutDownPreventionLock& /*proofOfLock*/) |
michael@0 | 1672 | { |
michael@0 | 1673 | if (!aCertList) |
michael@0 | 1674 | return nullptr; |
michael@0 | 1675 | |
michael@0 | 1676 | CERTCertList* newList = CERT_NewCertList(); |
michael@0 | 1677 | |
michael@0 | 1678 | if (!newList) { |
michael@0 | 1679 | return nullptr; |
michael@0 | 1680 | } |
michael@0 | 1681 | |
michael@0 | 1682 | CERTCertListNode* node; |
michael@0 | 1683 | for (node = CERT_LIST_HEAD(aCertList); !CERT_LIST_END(node, aCertList); |
michael@0 | 1684 | node = CERT_LIST_NEXT(node)) { |
michael@0 | 1685 | CERTCertificate* cert = CERT_DupCertificate(node->cert); |
michael@0 | 1686 | CERT_AddCertToListTail(newList, cert); |
michael@0 | 1687 | } |
michael@0 | 1688 | return newList; |
michael@0 | 1689 | } |
michael@0 | 1690 | |
michael@0 | 1691 | void* |
michael@0 | 1692 | nsNSSCertList::GetRawCertList() |
michael@0 | 1693 | { |
michael@0 | 1694 | // This function should only be called after adquiring a |
michael@0 | 1695 | // nsNSSShutDownPreventionLock |
michael@0 | 1696 | return mCertList.get(); |
michael@0 | 1697 | } |
michael@0 | 1698 | |
michael@0 | 1699 | NS_IMETHODIMP |
michael@0 | 1700 | nsNSSCertList::GetEnumerator(nsISimpleEnumerator** _retval) |
michael@0 | 1701 | { |
michael@0 | 1702 | nsNSSShutDownPreventionLock locker; |
michael@0 | 1703 | if (isAlreadyShutDown()) { |
michael@0 | 1704 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 1705 | } |
michael@0 | 1706 | nsCOMPtr<nsISimpleEnumerator> enumerator = |
michael@0 | 1707 | new nsNSSCertListEnumerator(mCertList.get(), locker); |
michael@0 | 1708 | |
michael@0 | 1709 | *_retval = enumerator; |
michael@0 | 1710 | NS_ADDREF(*_retval); |
michael@0 | 1711 | return NS_OK; |
michael@0 | 1712 | } |
michael@0 | 1713 | |
michael@0 | 1714 | NS_IMPL_ISUPPORTS(nsNSSCertListEnumerator, nsISimpleEnumerator) |
michael@0 | 1715 | |
michael@0 | 1716 | nsNSSCertListEnumerator::nsNSSCertListEnumerator( |
michael@0 | 1717 | CERTCertList* certList, const nsNSSShutDownPreventionLock& proofOfLock) |
michael@0 | 1718 | { |
michael@0 | 1719 | mCertList = nsNSSCertList::DupCertList(certList, proofOfLock); |
michael@0 | 1720 | } |
michael@0 | 1721 | |
michael@0 | 1722 | nsNSSCertListEnumerator::~nsNSSCertListEnumerator() |
michael@0 | 1723 | { |
michael@0 | 1724 | nsNSSShutDownPreventionLock locker; |
michael@0 | 1725 | if (isAlreadyShutDown()) { |
michael@0 | 1726 | return; |
michael@0 | 1727 | } |
michael@0 | 1728 | destructorSafeDestroyNSSReference(); |
michael@0 | 1729 | shutdown(calledFromObject); |
michael@0 | 1730 | } |
michael@0 | 1731 | |
michael@0 | 1732 | void nsNSSCertListEnumerator::virtualDestroyNSSReference() |
michael@0 | 1733 | { |
michael@0 | 1734 | destructorSafeDestroyNSSReference(); |
michael@0 | 1735 | } |
michael@0 | 1736 | |
michael@0 | 1737 | void nsNSSCertListEnumerator::destructorSafeDestroyNSSReference() |
michael@0 | 1738 | { |
michael@0 | 1739 | if (mCertList) { |
michael@0 | 1740 | mCertList = nullptr; |
michael@0 | 1741 | } |
michael@0 | 1742 | } |
michael@0 | 1743 | |
michael@0 | 1744 | NS_IMETHODIMP |
michael@0 | 1745 | nsNSSCertListEnumerator::HasMoreElements(bool* _retval) |
michael@0 | 1746 | { |
michael@0 | 1747 | nsNSSShutDownPreventionLock locker; |
michael@0 | 1748 | if (isAlreadyShutDown()) { |
michael@0 | 1749 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 1750 | } |
michael@0 | 1751 | |
michael@0 | 1752 | NS_ENSURE_TRUE(mCertList, NS_ERROR_FAILURE); |
michael@0 | 1753 | |
michael@0 | 1754 | *_retval = !CERT_LIST_EMPTY(mCertList); |
michael@0 | 1755 | return NS_OK; |
michael@0 | 1756 | } |
michael@0 | 1757 | |
michael@0 | 1758 | NS_IMETHODIMP |
michael@0 | 1759 | nsNSSCertListEnumerator::GetNext(nsISupports** _retval) |
michael@0 | 1760 | { |
michael@0 | 1761 | nsNSSShutDownPreventionLock locker; |
michael@0 | 1762 | if (isAlreadyShutDown()) { |
michael@0 | 1763 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 1764 | } |
michael@0 | 1765 | |
michael@0 | 1766 | NS_ENSURE_TRUE(mCertList, NS_ERROR_FAILURE); |
michael@0 | 1767 | |
michael@0 | 1768 | CERTCertListNode* node = CERT_LIST_HEAD(mCertList); |
michael@0 | 1769 | if (CERT_LIST_END(node, mCertList)) { |
michael@0 | 1770 | return NS_ERROR_FAILURE; |
michael@0 | 1771 | } |
michael@0 | 1772 | |
michael@0 | 1773 | nsCOMPtr<nsIX509Cert> nssCert = nsNSSCertificate::Create(node->cert); |
michael@0 | 1774 | if (!nssCert) { |
michael@0 | 1775 | return NS_ERROR_OUT_OF_MEMORY; |
michael@0 | 1776 | } |
michael@0 | 1777 | |
michael@0 | 1778 | *_retval = nssCert; |
michael@0 | 1779 | NS_ADDREF(*_retval); |
michael@0 | 1780 | |
michael@0 | 1781 | CERT_RemoveCertListNode(node); |
michael@0 | 1782 | return NS_OK; |
michael@0 | 1783 | } |
michael@0 | 1784 | |
michael@0 | 1785 | // NB: This serialization must match that of nsNSSCertificateFakeTransport. |
michael@0 | 1786 | NS_IMETHODIMP |
michael@0 | 1787 | nsNSSCertificate::Write(nsIObjectOutputStream* aStream) |
michael@0 | 1788 | { |
michael@0 | 1789 | NS_ENSURE_STATE(mCert); |
michael@0 | 1790 | nsresult rv = aStream->Write32(static_cast<uint32_t>(mCachedEVStatus)); |
michael@0 | 1791 | if (NS_FAILED(rv)) { |
michael@0 | 1792 | return rv; |
michael@0 | 1793 | } |
michael@0 | 1794 | rv = aStream->Write32(mCert->derCert.len); |
michael@0 | 1795 | if (NS_FAILED(rv)) { |
michael@0 | 1796 | return rv; |
michael@0 | 1797 | } |
michael@0 | 1798 | return aStream->WriteByteArray(mCert->derCert.data, mCert->derCert.len); |
michael@0 | 1799 | } |
michael@0 | 1800 | |
michael@0 | 1801 | NS_IMETHODIMP |
michael@0 | 1802 | nsNSSCertificate::Read(nsIObjectInputStream* aStream) |
michael@0 | 1803 | { |
michael@0 | 1804 | NS_ENSURE_STATE(!mCert); |
michael@0 | 1805 | |
michael@0 | 1806 | uint32_t cachedEVStatus; |
michael@0 | 1807 | nsresult rv = aStream->Read32(&cachedEVStatus); |
michael@0 | 1808 | if (NS_FAILED(rv)) { |
michael@0 | 1809 | return rv; |
michael@0 | 1810 | } |
michael@0 | 1811 | if (cachedEVStatus == static_cast<uint32_t>(ev_status_unknown)) { |
michael@0 | 1812 | mCachedEVStatus = ev_status_unknown; |
michael@0 | 1813 | } else if (cachedEVStatus == static_cast<uint32_t>(ev_status_valid)) { |
michael@0 | 1814 | mCachedEVStatus = ev_status_valid; |
michael@0 | 1815 | } else if (cachedEVStatus == static_cast<uint32_t>(ev_status_invalid)) { |
michael@0 | 1816 | mCachedEVStatus = ev_status_invalid; |
michael@0 | 1817 | } else { |
michael@0 | 1818 | return NS_ERROR_UNEXPECTED; |
michael@0 | 1819 | } |
michael@0 | 1820 | |
michael@0 | 1821 | uint32_t len; |
michael@0 | 1822 | rv = aStream->Read32(&len); |
michael@0 | 1823 | if (NS_FAILED(rv)) { |
michael@0 | 1824 | return rv; |
michael@0 | 1825 | } |
michael@0 | 1826 | |
michael@0 | 1827 | nsXPIDLCString str; |
michael@0 | 1828 | rv = aStream->ReadBytes(len, getter_Copies(str)); |
michael@0 | 1829 | if (NS_FAILED(rv)) { |
michael@0 | 1830 | return rv; |
michael@0 | 1831 | } |
michael@0 | 1832 | |
michael@0 | 1833 | if (!InitFromDER(const_cast<char*>(str.get()), len)) { |
michael@0 | 1834 | return NS_ERROR_UNEXPECTED; |
michael@0 | 1835 | } |
michael@0 | 1836 | |
michael@0 | 1837 | return NS_OK; |
michael@0 | 1838 | } |
michael@0 | 1839 | |
michael@0 | 1840 | NS_IMETHODIMP |
michael@0 | 1841 | nsNSSCertificate::GetInterfaces(uint32_t* count, nsIID*** array) |
michael@0 | 1842 | { |
michael@0 | 1843 | *count = 0; |
michael@0 | 1844 | *array = nullptr; |
michael@0 | 1845 | return NS_OK; |
michael@0 | 1846 | } |
michael@0 | 1847 | |
michael@0 | 1848 | NS_IMETHODIMP |
michael@0 | 1849 | nsNSSCertificate::GetHelperForLanguage(uint32_t language, |
michael@0 | 1850 | nsISupports** _retval) |
michael@0 | 1851 | { |
michael@0 | 1852 | *_retval = nullptr; |
michael@0 | 1853 | return NS_OK; |
michael@0 | 1854 | } |
michael@0 | 1855 | |
michael@0 | 1856 | NS_IMETHODIMP |
michael@0 | 1857 | nsNSSCertificate::GetContractID(char** aContractID) |
michael@0 | 1858 | { |
michael@0 | 1859 | *aContractID = nullptr; |
michael@0 | 1860 | return NS_OK; |
michael@0 | 1861 | } |
michael@0 | 1862 | |
michael@0 | 1863 | NS_IMETHODIMP |
michael@0 | 1864 | nsNSSCertificate::GetClassDescription(char** aClassDescription) |
michael@0 | 1865 | { |
michael@0 | 1866 | *aClassDescription = nullptr; |
michael@0 | 1867 | return NS_OK; |
michael@0 | 1868 | } |
michael@0 | 1869 | |
michael@0 | 1870 | NS_IMETHODIMP |
michael@0 | 1871 | nsNSSCertificate::GetClassID(nsCID** aClassID) |
michael@0 | 1872 | { |
michael@0 | 1873 | *aClassID = (nsCID*) nsMemory::Alloc(sizeof(nsCID)); |
michael@0 | 1874 | if (!*aClassID) |
michael@0 | 1875 | return NS_ERROR_OUT_OF_MEMORY; |
michael@0 | 1876 | return GetClassIDNoAlloc(*aClassID); |
michael@0 | 1877 | } |
michael@0 | 1878 | |
michael@0 | 1879 | NS_IMETHODIMP |
michael@0 | 1880 | nsNSSCertificate::GetImplementationLanguage(uint32_t* aImplementationLanguage) |
michael@0 | 1881 | { |
michael@0 | 1882 | *aImplementationLanguage = nsIProgrammingLanguage::CPLUSPLUS; |
michael@0 | 1883 | return NS_OK; |
michael@0 | 1884 | } |
michael@0 | 1885 | |
michael@0 | 1886 | NS_IMETHODIMP |
michael@0 | 1887 | nsNSSCertificate::GetFlags(uint32_t* aFlags) |
michael@0 | 1888 | { |
michael@0 | 1889 | *aFlags = nsIClassInfo::THREADSAFE; |
michael@0 | 1890 | return NS_OK; |
michael@0 | 1891 | } |
michael@0 | 1892 | |
michael@0 | 1893 | NS_IMETHODIMP |
michael@0 | 1894 | nsNSSCertificate::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) |
michael@0 | 1895 | { |
michael@0 | 1896 | static NS_DEFINE_CID(kNSSCertificateCID, NS_X509CERT_CID); |
michael@0 | 1897 | |
michael@0 | 1898 | *aClassIDNoAlloc = kNSSCertificateCID; |
michael@0 | 1899 | return NS_OK; |
michael@0 | 1900 | } |