// Tests that a critical extension not in the id-ce or id-pe arcs (which is
// thus unknown to us) is detected and that verification fails with the
// appropriate error.
TEST_F(pkix_cert_extensions, UnknownCriticalExtension)
{
  static const uint8_t unknownCriticalExtensionBytes[] = {
    0x30, 0x19, // SEQUENCE (length = 25)
      0x06, 0x12, // OID (length = 18)
        // 1.3.6.1.4.1.13769.666.666.666.1.500.9.3
        0x2b, 0x06, 0x01, 0x04, 0x01, 0xeb, 0x49, 0x85, 0x1a,
        0x85, 0x1a, 0x85, 0x1a, 0x01, 0x83, 0x74, 0x09, 0x03,
      0x01, 0x01, 0xff, // BOOLEAN (length = 1) TRUE
      0x04, 0x00 // OCTET STRING (length = 0)
  };
  static const SECItem unknownCriticalExtension = {
    siBuffer,
    const_cast<unsigned char*>(unknownCriticalExtensionBytes),
    sizeof(unknownCriticalExtensionBytes)
  };
  const char* certCN = "CN=Cert With Unknown Critical Extension";
  ScopedSECKEYPrivateKey key;
  ScopedCERTCertificate cert;
  ASSERT_TRUE(CreateCert(arena.get(), certCN, &unknownCriticalExtension, key,
                         cert));
  ScopedCERTCertList results;
  ASSERT_SECFailure(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION,
                    BuildCertChain(trustDomain, cert.get(),
                                   now, EndEntityOrCA::MustBeEndEntity,
                                   0, // key usage
                                   KeyPurposeId::anyExtendedKeyUsage,
                                   CertPolicyId::anyPolicy,
                                   nullptr, // stapled OCSP response
                                   results));
}
// Creates a self-signed certificate with the given extension.
static bool
CreateCert(PLArenaPool* arena, const char* subjectStr,
           const SECItem* extension,
           /*out*/ ScopedSECKEYPrivateKey& subjectKey,
           /*out*/ ScopedCERTCertificate& subjectCert)
{
  static long serialNumberValue = 0;
  ++serialNumberValue;
  const SECItem* serialNumber(CreateEncodedSerialNumber(arena,
                                                        serialNumberValue));
  if (!serialNumber) {
    return false;
  }
  const SECItem* issuerDER(ASCIIToDERName(arena, subjectStr));
  if (!issuerDER) {
    return false;
  }
  const SECItem* subjectDER(ASCIIToDERName(arena, subjectStr));
  if (!subjectDER) {
    return false;
  }

  const SECItem* extensions[2] = { extension, nullptr };

  SECItem* certDER(CreateEncodedCertificate(arena, v3, SEC_OID_SHA256,
                                            serialNumber, issuerDER,
                                            PR_Now() - ONE_DAY,
                                            PR_Now() + ONE_DAY,
                                            subjectDER, extensions,
                                            nullptr, SEC_OID_SHA256,
                                            subjectKey));
  if (!certDER) {
    return false;
  }
  subjectCert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), certDER,
                                        nullptr, false, true);
  return subjectCert.get() != nullptr;
}
Example #3
0
NS_IMETHODIMP 
nsNSSCertificateDB::ImportUserCertificate(uint8_t *data, uint32_t length, nsIInterfaceRequestor *ctx)
{
  if (!NS_IsMainThread()) {
    NS_ERROR("nsNSSCertificateDB::ImportUserCertificate called off the main thread");
    return NS_ERROR_NOT_SAME_THREAD;
  }
  
  nsNSSShutDownPreventionLock locker;
  if (isAlreadyShutDown()) {
    return NS_ERROR_NOT_AVAILABLE;
  }

  ScopedPK11SlotInfo slot;
  nsAutoCString nickname;
  nsresult rv = NS_ERROR_FAILURE;
  int numCACerts;
  SECItem *CACerts;
  CERTDERCerts * collectArgs;
  PLArenaPool *arena;
  ScopedCERTCertificate cert;

  arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  if (!arena) {
    goto loser;
  }

  collectArgs = getCertsFromPackage(arena, data, length, locker);
  if (!collectArgs) {
    goto loser;
  }

  cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), collectArgs->rawCerts,
                                 nullptr, false, true);
  if (!cert) {
    goto loser;
  }

  slot = PK11_KeyForCertExists(cert.get(), nullptr, ctx);
  if (!slot) {
    nsCOMPtr<nsIX509Cert> certToShow = nsNSSCertificate::Create(cert.get());
    DisplayCertificateAlert(ctx, "UserCertIgnoredNoPrivateKey", certToShow, locker);
    goto loser;
  }
  slot = nullptr;

  /* pick a nickname for the cert */
  if (cert->nickname) {
	/* sigh, we need a call to look up other certs with this subject and
	 * identify nicknames from them. We can no longer walk down internal
	 * database structures  rjr */
  	nickname = cert->nickname;
  }
  else {
    get_default_nickname(cert.get(), ctx, nickname, locker);
  }

  /* user wants to import the cert */
  {
    char *cast_const_away = const_cast<char*>(nickname.get());
    slot = PK11_ImportCertForKey(cert.get(), cast_const_away, ctx);
  }
  if (!slot) {
    goto loser;
  }
  slot = nullptr;

  {
    nsCOMPtr<nsIX509Cert> certToShow = nsNSSCertificate::Create(cert.get());
    DisplayCertificateAlert(ctx, "UserCertImported", certToShow, locker);
  }
  rv = NS_OK;

  numCACerts = collectArgs->numcerts - 1;
  if (numCACerts) {
    CACerts = collectArgs->rawCerts+1;
    rv = ImportValidCACerts(numCACerts, CACerts, ctx, locker);
  }
  
loser:
  if (arena) {
    PORT_FreeArena(arena, false);
  }
  return rv;
}
Example #4
0
SECItemArray *
GetOCSPResponseForType(OCSPResponseType aORT, CERTCertificate *aCert,
                       PLArenaPool *aArena, const char *aAdditionalCertName)
{
  if (aORT == ORTNone) {
    if (gDebugLevel >= DEBUG_WARNINGS) {
      fprintf(stderr, "GetOCSPResponseForType called with type ORTNone, "
                      "which makes no sense.\n");
    }
    return nullptr;
  }

  if (aORT == ORTEmpty) {
    SECItemArray* arr = SECITEM_AllocArray(aArena, nullptr, 1);
    arr->items[0].data = nullptr;
    arr->items[0].len = 0;
    return arr;
  }

  PRTime now = PR_Now();
  PRTime oneDay = 60*60*24 * (PRTime)PR_USEC_PER_SEC;
  PRTime oldNow = now - (8 * oneDay);

  OCSPResponseContext context(aArena, aCert, now);

  if (aORT == ORTGoodOtherCert) {
    context.cert = PK11_FindCertFromNickname(aAdditionalCertName, nullptr);
    if (!context.cert) {
      PrintPRError("PK11_FindCertFromNickname failed");
      return nullptr;
    }
  }
  // XXX CERT_FindCertIssuer uses the old, deprecated path-building logic
  ScopedCERTCertificate issuerCert(CERT_FindCertIssuer(aCert, now,
                                                       certUsageSSLCA));
  if (!issuerCert) {
    PrintPRError("CERT_FindCertIssuer failed");
    return nullptr;
  }
  context.issuerNameDER = &issuerCert->derSubject;
  context.issuerSPKI = &issuerCert->subjectPublicKeyInfo;
  ScopedCERTCertificate signerCert;
  if (aORT == ORTGoodOtherCA || aORT == ORTDelegatedIncluded ||
      aORT == ORTDelegatedIncludedLast || aORT == ORTDelegatedMissing ||
      aORT == ORTDelegatedMissingMultiple) {
    signerCert = PK11_FindCertFromNickname(aAdditionalCertName, nullptr);
    if (!signerCert) {
      PrintPRError("PK11_FindCertFromNickname failed");
      return nullptr;
    }
  }

  const SECItem* certs[5] = { nullptr, nullptr, nullptr, nullptr, nullptr };

  if (aORT == ORTDelegatedIncluded) {
    certs[0] = &signerCert->derCert;
    context.certs = certs;
  }
  if (aORT == ORTDelegatedIncludedLast || aORT == ORTDelegatedMissingMultiple) {
    certs[0] = &issuerCert->derCert;
    certs[1] = &context.cert->derCert;
    certs[2] = &issuerCert->derCert;
    if (aORT != ORTDelegatedMissingMultiple) {
      certs[3] = &signerCert->derCert;
    }
    context.certs = certs;
  }

  switch (aORT) {
    case ORTMalformed:
      context.responseStatus = 1;
      break;
    case ORTSrverr:
      context.responseStatus = 2;
      break;
    case ORTTryLater:
      context.responseStatus = 3;
      break;
    case ORTNeedsSig:
      context.responseStatus = 5;
      break;
    case ORTUnauthorized:
      context.responseStatus = 6;
      break;
    default:
      // context.responseStatus is 0 in all other cases, and it has
      // already been initialized in the constructor.
      break;
  }
  if (aORT == ORTSkipResponseBytes) {
    context.skipResponseBytes = true;
  }
  if (aORT == ORTExpired || aORT == ORTExpiredFreshCA) {
    context.thisUpdate = oldNow;
    context.nextUpdate = oldNow + 10 * PR_USEC_PER_SEC;
  }
  if (aORT == ORTRevoked) {
    context.certStatus = 1;
  }
  if (aORT == ORTUnknown) {
    context.certStatus = 2;
  }
  if (aORT == ORTBadSignature) {
    context.badSignature = true;
  }
  OCSPResponseExtension extension;
  if (aORT == ORTCriticalExtension || aORT == ORTNoncriticalExtension) {
    SECItem oidItem = {
      siBuffer,
      nullptr,
      0
    };
    // 1.3.6.1.4.1.13769.666.666.666 is the root of Mozilla's testing OID space
    static const char* testExtensionOID = "1.3.6.1.4.1.13769.666.666.666.1.500.9.2";
    if (SEC_StringToOID(aArena, &oidItem, testExtensionOID,
                        PL_strlen(testExtensionOID)) != SECSuccess) {
      return nullptr;
    }
    DERTemplate oidTemplate[2] = { { DER_OBJECT_ID, 0 }, { 0 } };
    extension.id.data = nullptr;
    extension.id.len = 0;
    if (DER_Encode(aArena, &extension.id, oidTemplate, &oidItem)
          != SECSuccess) {
      return nullptr;
    }
    extension.critical = (aORT == ORTCriticalExtension);
    static const uint8_t value[2] = { 0x05, 0x00 };
    extension.value.data = const_cast<uint8_t*>(value);
    extension.value.len = PR_ARRAY_SIZE(value);
    extension.next = nullptr;
    context.extensions = &extension;
  }
  if (aORT == ORTEmptyExtensions) {
    context.includeEmptyExtensions = true;
  }

  if (!signerCert) {
    signerCert = CERT_DupCertificate(issuerCert.get());
  }
  context.signerPrivateKey = PK11_FindKeyByAnyCert(signerCert.get(), nullptr);
  if (!context.signerPrivateKey) {
    PrintPRError("PK11_FindKeyByAnyCert failed");
    return nullptr;
  }

  SECItem* response = CreateEncodedOCSPResponse(context);
  if (!response) {
    PrintPRError("CreateEncodedOCSPResponse failed");
    return nullptr;
  }

  SECItemArray* arr = SECITEM_AllocArray(aArena, nullptr, 1);
  if (!arr) {
    PrintPRError("SECITEM_AllocArray failed");
    return nullptr;
  }
  arr->items[0].data = response->data;
  arr->items[0].len = response->len;

  return arr;
}