Beispiel #1
0
/* Initialize the extension data block. */
void
ssl3_InitExtensionData(TLSExtensionData *xtnData, const sslSocket *ss)
{
    unsigned int advertisedMax;
    PRCList *cursor;

    /* Set things up to the right starting state. */
    PORT_Memset(xtnData, 0, sizeof(*xtnData));
    xtnData->peerSupportsFfdheGroups = PR_FALSE;
    PR_INIT_CLIST(&xtnData->remoteKeyShares);

    /* Allocate enough to allow for native extensions, plus any custom ones. */
    if (ss->sec.isServer) {
        advertisedMax = PR_MAX(PR_ARRAY_SIZE(certificateRequestHandlers),
                               PR_ARRAY_SIZE(tls13_cert_req_senders));
    } else {
        advertisedMax = PR_MAX(PR_ARRAY_SIZE(clientHelloHandlers),
                               PR_ARRAY_SIZE(clientHelloSendersTLS));
        ++advertisedMax; /* For the RI SCSV, which we also track. */
    }
    for (cursor = PR_NEXT_LINK(&ss->extensionHooks);
         cursor != &ss->extensionHooks;
         cursor = PR_NEXT_LINK(cursor)) {
        ++advertisedMax;
    }
    xtnData->advertised = PORT_ZNewArray(PRUint16, advertisedMax);
}
bool TransportLayerDtls::SetupCipherSuites(PRFileDesc* ssl_fd) const {
  SECStatus rv;

  // Set the SRTP ciphers
  if (!srtp_ciphers_.empty()) {
    // Note: std::vector is guaranteed to contiguous
    rv = SSL_SetSRTPCiphers(ssl_fd, &srtp_ciphers_[0], srtp_ciphers_.size());

    if (rv != SECSuccess) {
      MOZ_MTLOG(ML_ERROR, "Couldn't set SRTP cipher suite");
      return false;
    }
  }

  for (size_t i = 0; i < PR_ARRAY_SIZE(EnabledCiphers); ++i) {
    MOZ_MTLOG(ML_INFO, LAYER_INFO << "Enabling: " << EnabledCiphers[i]);
    rv = SSL_CipherPrefSet(ssl_fd, EnabledCiphers[i], PR_TRUE);
    if (rv != SECSuccess) {
      MOZ_MTLOG(ML_ERROR, LAYER_INFO <<
                "Unable to enable suite: " << EnabledCiphers[i]);
      return false;
    }
  }

// Don't remove suites; TODO([email protected]) restore; bug 1052610
#if 0
  for (size_t i = 0; i < PR_ARRAY_SIZE(DisabledCiphers); ++i) {
    MOZ_MTLOG(ML_INFO, LAYER_INFO << "Disabling: " << DisabledCiphers[i]);

    PRBool enabled = false;
    rv = SSL_CipherPrefGet(ssl_fd, DisabledCiphers[i], &enabled);
    if (rv != SECSuccess) {
      MOZ_MTLOG(ML_NOTICE, LAYER_INFO <<
                "Unable to check if suite is enabled: " << DisabledCiphers[i]);
      return false;
    }
    if (enabled) {
      rv = SSL_CipherPrefSet(ssl_fd, DisabledCiphers[i], PR_FALSE);
      if (rv != SECSuccess) {
        MOZ_MTLOG(ML_NOTICE, LAYER_INFO <<
                  "Unable to disable suite: " << DisabledCiphers[i]);
        return false;
      }
    }
  }
#endif
  return true;
}
Beispiel #3
0
void
RegisterErrorTable()
{
  static const struct PRErrorMessage ErrorTableText[] = {
    { "MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE",
      "The server uses key pinning (HPKP) but no trusted certificate chain "
      "could be constructed that matches the pinset. Key pinning violations "
      "cannot be overridden." },
    { "MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY",
      "The server uses a certificate with a basic constraints extension "
      "identifying it as a certificate authority. For a properly-issued "
      "certificate, this should not be the case." },
    { "MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE",
      "The server presented a certificate with a key size that is too small "
      "to establish a secure connection." }
  };

  static const struct PRErrorTable ErrorTable = {
    ErrorTableText,
    "pkixerrors",
    ERROR_BASE,
    PR_ARRAY_SIZE(ErrorTableText)
  };

  (void) PR_ErrorInstallTable(&ErrorTable);
}
Beispiel #4
0
const ssl3MACDef *
ssl_GetMacDefByAlg(SSL3MACAlgorithm mac)
{
    /* Cast here for clang: https://bugs.llvm.org/show_bug.cgi?id=16154 */
    PORT_Assert((size_t)mac < PR_ARRAY_SIZE(ssl_mac_defs));
    PORT_Assert(ssl_mac_defs[mac].mac == mac);
    return &ssl_mac_defs[mac];
}
Beispiel #5
0
const ssl3BulkCipherDef *
ssl_GetBulkCipherDef(const ssl3CipherSuiteDef *suiteDef)
{
    SSL3BulkCipher bulkCipher = suiteDef->bulk_cipher_alg;
    PORT_Assert(bulkCipher < PR_ARRAY_SIZE(ssl_bulk_cipher_defs));
    PORT_Assert(ssl_bulk_cipher_defs[bulkCipher].cipher == bulkCipher);
    return &ssl_bulk_cipher_defs[bulkCipher];
}
// Returns the preload list entry for the given host, if it exists.
// Only does exact host matching - the user must decide how to use the returned
// data. May return null.
const nsSTSPreload *
nsStrictTransportSecurityService::GetPreloadListEntry(const char *aHost)
{
    return (const nsSTSPreload *) bsearch(aHost,
                                          kSTSPreloadList,
                                          PR_ARRAY_SIZE(kSTSPreloadList),
                                          sizeof(nsSTSPreload),
                                          STSPreloadCompare);
}
Beispiel #7
0
void
RegisterErrorTable()
{
  // Note that these error strings are not localizable.
  // When these strings change, update the localization information too.
  static const PRErrorMessage ErrorTableText[] = {
    { "MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE",
      "The server uses key pinning (HPKP) but no trusted certificate chain "
      "could be constructed that matches the pinset. Key pinning violations "
      "cannot be overridden." },
    { "MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY",
      "The server uses a certificate with a basic constraints extension "
      "identifying it as a certificate authority. For a properly-issued "
      "certificate, this should not be the case." },
    { "MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE",
      "The server presented a certificate with a key size that is too small "
      "to establish a secure connection." },
    { "MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA",
      "An X.509 version 1 certificate that is not a trust anchor was used to "
      "issue the server's certificate. X.509 version 1 certificates are "
      "deprecated and should not be used to sign other certificates." },
    { "MOZILLA_PKIX_ERROR_NO_RFC822NAME_MATCH",
      "The certificate is not valid for the given email address." },
    { "MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE",
      "The server presented a certificate that is not yet valid." },
    { "MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE",
      "A certificate that is not yet valid was used to issue the server's "
      "certificate." },
    { "MOZILLA_PKIX_ERROR_SIGNATURE_ALGORITHM_MISMATCH",
      "The signature algorithm in the signature field of the certificate does "
      "not match the algorithm in its signatureAlgorithm field." },
    { "MOZILLA_PKIX_ERROR_OCSP_RESPONSE_FOR_CERT_MISSING",
      "The OCSP response does not include a status for the certificate being "
      "verified." },
    { "MOZILLA_PKIX_ERROR_VALIDITY_TOO_LONG",
      "The server presented a certificate that is valid for too long." },
    { "MOZILLA_PKIX_ERROR_REQUIRED_TLS_FEATURE_MISSING",
      "A required TLS feature is missing." },
    { "MOZILLA_PKIX_ERROR_INVALID_INTEGER_ENCODING",
      "The server presented a certificate that contains an invalid encoding of "
      "an integer. Common causes include negative serial numbers, negative RSA "
      "moduli, and encodings that are longer than necessary." },
  };
  // Note that these error strings are not localizable.
  // When these strings change, update the localization information too.

  static const PRErrorTable ErrorTable = {
    ErrorTableText,
    "pkixerrors",
    ERROR_BASE,
    PR_ARRAY_SIZE(ErrorTableText)
  };

  (void) PR_ErrorInstallTable(&ErrorTable);
}
Beispiel #8
0
static SSLExtensionSupport
ssl_GetExtensionSupport(PRUint16 type)
{
    unsigned int i;
    for (i = 0; i < PR_ARRAY_SIZE(ssl_supported_extensions); ++i) {
        if (type == ssl_supported_extensions[i].type) {
            return ssl_supported_extensions[i].support;
        }
    }
    return ssl_ext_none;
}
Beispiel #9
0
static PRStatus
ssl_ECRegister(void)
{
    SECStatus rv;
    PORT_Assert(PR_ARRAY_SIZE(gECDHEKeyPairs) == ssl_named_group_count);
    rv = NSS_RegisterShutdown(ssl_ShutdownECDHECurves, gECDHEKeyPairs);
    if (rv != SECSuccess) {
        gECDHEInitError = PORT_GetError();
    }
    return (PRStatus)rv;
}
Beispiel #10
0
static bool
isEVPolicy(SECOidTag policyOIDTag)
{
  for (size_t iEV = 0; iEV < PR_ARRAY_SIZE(myTrustedEVInfos); ++iEV) {
    nsMyTrustedEVInfo& entry = myTrustedEVInfos[iEV];
    if (policyOIDTag == entry.oid_tag) {
      return true;
    }
  }

  return false;
}
Beispiel #11
0
// BasicOCSPResponse       ::= SEQUENCE {
//    tbsResponseData      ResponseData,
//    signatureAlgorithm   AlgorithmIdentifier,
//    signature            BIT STRING,
//    certs            [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
Result
BasicResponse(Input& input, Context& context)
{
  Input tbsResponseData;
  SignedDataWithSignature signedData;
  Result rv = der::SignedData(input, tbsResponseData, signedData);
  if (rv != Success) {
    if (PR_GetError() == SEC_ERROR_BAD_SIGNATURE) {
      return Fail(RecoverableError, SEC_ERROR_OCSP_BAD_SIGNATURE);
    }
    return rv;
  }

  // Parse certificates, if any

  SECItem certs[8];
  size_t numCerts = 0;

  if (!input.AtEnd()) {
    // We ignore the lengths of the wrappers because we'll detect bad lengths
    // during parsing--too short and we'll run out of input for parsing a cert,
    // and too long and we'll have leftover data that won't parse as a cert.

    // [0] wrapper
    rv = der::ExpectTagAndSkipLength(
          input, der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 0);
    if (rv != Success) {
      return rv;
    }

    // SEQUENCE wrapper
    rv = der::ExpectTagAndSkipLength(input, der::SEQUENCE);
    if (rv != Success) {
      return rv;
    }

    // sequence of certificates
    while (!input.AtEnd()) {
      if (numCerts == PR_ARRAY_SIZE(certs)) {
        return Fail(SEC_ERROR_BAD_DER);
      }

      rv = der::ExpectTagAndGetTLV(input, der::SEQUENCE, certs[numCerts]);
      if (rv != Success) {
        return rv;
      }
      ++numCerts;
    }
  }

  return ResponseData(tbsResponseData, context, signedData, certs, numCerts);
}
Beispiel #12
0
void
CleanupIdentityInfo()
{
  for (size_t iEV = 0; iEV < PR_ARRAY_SIZE(myTrustedEVInfos); ++iEV) {
    nsMyTrustedEVInfo &entry = myTrustedEVInfos[iEV];
    if (entry.cert) {
      CERT_DestroyCertificate(entry.cert);
      entry.cert = nullptr;
    }
  }

  memset(&sIdentityInfoCallOnce, 0, sizeof(PRCallOnceType));
}
Beispiel #13
0
/* function to clear out the lists */
static SECStatus
ssl_ShutdownECDHECurves(void *appData, void *nssData)
{
    int i;

    for (i = 0; i < PR_ARRAY_SIZE(gECDHEKeyPairs); i++) {
        if (gECDHEKeyPairs[i].pair) {
            ssl_FreeEphemeralKeyPair(gECDHEKeyPairs[i].pair);
        }
    }
    memset(gECDHEKeyPairs, 0, sizeof(gECDHEKeyPairs));
    return SECSuccess;
}
Beispiel #14
0
CERTCertList*
GetRootsForOid(SECOidTag oid_tag)
{
  CERTCertList* certList = CERT_NewCertList();
  if (!certList)
    return nullptr;

  for (size_t iEV = 0; iEV < PR_ARRAY_SIZE(myTrustedEVInfos); ++iEV) {
    nsMyTrustedEVInfo& entry = myTrustedEVInfos[iEV];
    if (entry.oid_tag == oid_tag) {
      addToCertListIfTrusted(certList, entry.cert);
    }
  }

  return certList;
}
Beispiel #15
0
void
RegisterErrorTable()
{
  static const struct PRErrorMessage ErrorTableText[] = {
    { "MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE",
      "The server uses key pinning (HPKP) but no trusted certificate chain "
      "could be constructed that matches the pinset. Key pinning violations "
      "cannot be overridden." }
  };

  static const struct PRErrorTable ErrorTable = {
    ErrorTableText,
    "pkixerrors",
    ERROR_BASE,
    PR_ARRAY_SIZE(ErrorTableText)
  };

  (void) PR_ErrorInstallTable(&ErrorTable);
}
// Returns the preload list entry for the given host, if it exists.
// Only does exact host matching - the user must decide how to use the returned
// data. May return null.
const nsSTSPreload *
nsStrictTransportSecurityService::GetPreloadListEntry(const char *aHost)
{
  PRTime currentTime = PR_Now();
  int32_t timeOffset = 0;
  nsresult rv = mozilla::Preferences::GetInt("test.currentTimeOffsetSeconds",
                                             &timeOffset);
  if (NS_SUCCEEDED(rv)) {
    currentTime += (PRTime(timeOffset) * PR_USEC_PER_SEC);
  }

  if (mUsePreloadList && currentTime < gPreloadListExpirationTime) {
    return (const nsSTSPreload *) bsearch(aHost,
                                          kSTSPreloadList,
                                          PR_ARRAY_SIZE(kSTSPreloadList),
                                          sizeof(nsSTSPreload),
                                          STSPreloadCompare);
  }

  return nullptr;
}
bool
CertIsAuthoritativeForEVPolicy(const CERTCertificate* cert,
                               const mozilla::pkix::CertPolicyId& policy)
{
  PR_ASSERT(cert);
  if (!cert) {
    return false;
  }

  for (size_t iEV = 0; iEV < PR_ARRAY_SIZE(myTrustedEVInfos); ++iEV) {
    nsMyTrustedEVInfo& entry = myTrustedEVInfos[iEV];
    if (entry.cert && CERT_CompareCerts(cert, entry.cert)) {
      const SECOidData* oidData = SECOID_FindOIDByTag(entry.oid_tag);
      if (oidData && oidData->oid.len == policy.numBytes &&
          !memcmp(oidData->oid.data, policy.bytes, policy.numBytes)) {
        return true;
      }
    }
  }

  return false;
}
Beispiel #18
0
void _PR_DumpThreads(PRFileDesc *fd)
{
    PRThread *t;
    PRIntn i;

    _PR_DumpPrintf(fd, "Current Thread:\n");
    t = _PR_MD_CURRENT_THREAD();
    _PR_DumpThread(fd, t);

    _PR_DumpPrintf(fd, "Runnable Threads:\n");
    for (i = 0; i < PR_ARRAY_SIZE(_PR_RUNQ(t->cpu)); i++) {
        DumpThreadQueue(fd, &_PR_RUNQ(t->cpu)[i]);
    }

    _PR_DumpPrintf(fd, "CondVar timed wait Threads:\n");
    DumpThreadQueue(fd, &_PR_SLEEPQ(t->cpu));

    _PR_DumpPrintf(fd, "CondVar wait Threads:\n");
    DumpThreadQueue(fd, &_PR_PAUSEQ(t->cpu));

    _PR_DumpPrintf(fd, "Suspended Threads:\n");
    DumpThreadQueue(fd, &_PR_SUSPENDQ(t->cpu));
}
Beispiel #19
0
SECKEYPrivateKey*
CryptoKey::PrivateKeyFromJwk(const JsonWebKey& aJwk,
                             const nsNSSShutDownPreventionLock& /*proofOfLock*/)
{
  CK_OBJECT_CLASS privateKeyValue = CKO_PRIVATE_KEY;
  CK_BBOOL falseValue = CK_FALSE;

  if (aJwk.mKty.EqualsLiteral(JWK_TYPE_EC)) {
    // Verify that all of the required parameters are present
    CryptoBuffer x, y, d;
    if (!aJwk.mCrv.WasPassed() ||
        !aJwk.mX.WasPassed() || NS_FAILED(x.FromJwkBase64(aJwk.mX.Value())) ||
        !aJwk.mY.WasPassed() || NS_FAILED(y.FromJwkBase64(aJwk.mY.Value())) ||
        !aJwk.mD.WasPassed() || NS_FAILED(d.FromJwkBase64(aJwk.mD.Value()))) {
      return nullptr;
    }

    nsString namedCurve;
    if (!NormalizeToken(aJwk.mCrv.Value(), namedCurve)) {
      return nullptr;
    }

    ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
    if (!arena) {
      return nullptr;
    }

    // Create parameters.
    SECItem* params = CreateECParamsForCurve(namedCurve, arena.get());
    if (!params) {
      return nullptr;
    }

    SECItem* ecPoint = CreateECPointForCoordinates(x, y, arena.get());
    if (!ecPoint) {
      return nullptr;
    }

    // Compute the ID for this key
    // This is generated with a SHA-1 hash, so unlikely to collide
    ScopedSECItem objID(PK11_MakeIDFromPubKey(ecPoint));
    if (!objID.get()) {
      return nullptr;
    }

    // Populate template from parameters
    CK_KEY_TYPE ecValue = CKK_EC;
    CK_ATTRIBUTE keyTemplate[9] = {
      { CKA_CLASS,            &privateKeyValue,     sizeof(privateKeyValue) },
      { CKA_KEY_TYPE,         &ecValue,             sizeof(ecValue) },
      { CKA_TOKEN,            &falseValue,          sizeof(falseValue) },
      { CKA_SENSITIVE,        &falseValue,          sizeof(falseValue) },
      { CKA_PRIVATE,          &falseValue,          sizeof(falseValue) },
      { CKA_ID,               objID->data,          objID->len },
      { CKA_EC_PARAMS,        params->data,         params->len },
      { CKA_EC_POINT,         ecPoint->data,        ecPoint->len },
      { CKA_VALUE,            (void*) d.Elements(), d.Length() },
    };

    return PrivateKeyFromPrivateKeyTemplate(objID, keyTemplate,
                                            PR_ARRAY_SIZE(keyTemplate));
  }

  if (aJwk.mKty.EqualsLiteral(JWK_TYPE_RSA)) {
    // Verify that all of the required parameters are present
    CryptoBuffer n, e, d, p, q, dp, dq, qi;
    if (!aJwk.mN.WasPassed() || NS_FAILED(n.FromJwkBase64(aJwk.mN.Value())) ||
        !aJwk.mE.WasPassed() || NS_FAILED(e.FromJwkBase64(aJwk.mE.Value())) ||
        !aJwk.mD.WasPassed() || NS_FAILED(d.FromJwkBase64(aJwk.mD.Value())) ||
        !aJwk.mP.WasPassed() || NS_FAILED(p.FromJwkBase64(aJwk.mP.Value())) ||
        !aJwk.mQ.WasPassed() || NS_FAILED(q.FromJwkBase64(aJwk.mQ.Value())) ||
        !aJwk.mDp.WasPassed() || NS_FAILED(dp.FromJwkBase64(aJwk.mDp.Value())) ||
        !aJwk.mDq.WasPassed() || NS_FAILED(dq.FromJwkBase64(aJwk.mDq.Value())) ||
        !aJwk.mQi.WasPassed() || NS_FAILED(qi.FromJwkBase64(aJwk.mQi.Value()))) {
      return nullptr;
    }

    ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
    if (!arena) {
      return nullptr;
    }

    // Compute the ID for this key
    // This is generated with a SHA-1 hash, so unlikely to collide
    SECItem nItem = { siBuffer, nullptr, 0 };
    if (!n.ToSECItem(arena, &nItem)) {
      return nullptr;
    }

    ScopedSECItem objID(PK11_MakeIDFromPubKey(&nItem));
    if (!objID.get()) {
      return nullptr;
    }

    // Populate template from parameters
    CK_KEY_TYPE rsaValue = CKK_RSA;
    CK_ATTRIBUTE keyTemplate[14] = {
      { CKA_CLASS,            &privateKeyValue,      sizeof(privateKeyValue) },
      { CKA_KEY_TYPE,         &rsaValue,             sizeof(rsaValue) },
      { CKA_TOKEN,            &falseValue,           sizeof(falseValue) },
      { CKA_SENSITIVE,        &falseValue,           sizeof(falseValue) },
      { CKA_PRIVATE,          &falseValue,           sizeof(falseValue) },
      { CKA_ID,               objID->data,           objID->len },
      { CKA_MODULUS,          (void*) n.Elements(),  n.Length() },
      { CKA_PUBLIC_EXPONENT,  (void*) e.Elements(),  e.Length() },
      { CKA_PRIVATE_EXPONENT, (void*) d.Elements(),  d.Length() },
      { CKA_PRIME_1,          (void*) p.Elements(),  p.Length() },
      { CKA_PRIME_2,          (void*) q.Elements(),  q.Length() },
      { CKA_EXPONENT_1,       (void*) dp.Elements(), dp.Length() },
      { CKA_EXPONENT_2,       (void*) dq.Elements(), dq.Length() },
      { CKA_COEFFICIENT,      (void*) qi.Elements(), qi.Length() },
    };

    return PrivateKeyFromPrivateKeyTemplate(objID, keyTemplate,
                                            PR_ARRAY_SIZE(keyTemplate));
  }

  return nullptr;
}
Beispiel #20
0
SECItem*
CreateEncodedOCSPRequest(PLArenaPool* arena,
                         const CERTCertificate* cert,
                         const CERTCertificate* issuerCert)
{
  if (!arena || !cert || !issuerCert) {
    PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
    return nullptr;
  }

  // We do not add any extensions to the request.

  // RFC 6960 says "An OCSP client MAY wish to specify the kinds of response
  // types it understands. To do so, it SHOULD use an extension with the OID
  // id-pkix-ocsp-response." This use of MAY and SHOULD is unclear. MSIE11
  // on Windows 8.1 does not include any extensions, whereas NSS has always
  // included the id-pkix-ocsp-response extension. Avoiding the sending the
  // extension is better for OCSP GET because it makes the request smaller,
  // and thus more likely to fit within the 255 byte limit for OCSP GET that
  // is specified in RFC 5019 Section 5.

  // Bug 966856: Add the id-pkix-ocsp-pref-sig-algs extension.

  // Since we don't know whether the OCSP responder supports anything other
  // than SHA-1, we have no choice but to use SHA-1 for issuerNameHash and
  // issuerKeyHash.
  static const uint8_t hashAlgorithm[11] = {
    0x30, 0x09,                               // SEQUENCE
    0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, //   OBJECT IDENTIFIER id-sha1
    0x05, 0x00,                               //   NULL
  };
  static const uint8_t hashLen = SHA1_LENGTH;

  static const unsigned int totalLenWithoutSerialNumberData
    = 2                             // OCSPRequest
    + 2                             //   tbsRequest
    + 2                             //     requestList
    + 2                             //       Request
    + 2                             //         reqCert (CertID)
    + PR_ARRAY_SIZE(hashAlgorithm)  //           hashAlgorithm
    + 2 + hashLen                   //           issuerNameHash
    + 2 + hashLen                   //           issuerKeyHash
    + 2;                            //           serialNumber (header)

  // The only way we could have a request this large is if the serialNumber was
  // ridiculously and unreasonably large. RFC 5280 says "Conforming CAs MUST
  // NOT use serialNumber values longer than 20 octets." With this restriction,
  // we allow for some amount of non-conformance with that requirement while
  // still ensuring we can encode the length values in the ASN.1 TLV structures
  // in a single byte.
  if (issuerCert->serialNumber.len > 127u - totalLenWithoutSerialNumberData) {
    PR_SetError(SEC_ERROR_BAD_DATA, 0);
    return nullptr;
  }

  uint8_t totalLen = static_cast<uint8_t>(totalLenWithoutSerialNumberData +
    cert->serialNumber.len);

  SECItem* encodedRequest = SECITEM_AllocItem(arena, nullptr, totalLen);
  if (!encodedRequest) {
    return nullptr;
  }

  uint8_t* d = encodedRequest->data;
  *d++ = 0x30; *d++ = totalLen - 2;  // OCSPRequest (SEQUENCE)
  *d++ = 0x30; *d++ = totalLen - 4;  //   tbsRequest (SEQUENCE)
  *d++ = 0x30; *d++ = totalLen - 6;  //     requestList (SEQUENCE OF)
  *d++ = 0x30; *d++ = totalLen - 8;  //       Request (SEQUENCE)
  *d++ = 0x30; *d++ = totalLen - 10; //         reqCert (CertID SEQUENCE)

  // reqCert.hashAlgorithm
  for (size_t i = 0; i < PR_ARRAY_SIZE(hashAlgorithm); ++i) {
    *d++ = hashAlgorithm[i];
  }

  // reqCert.issuerNameHash (OCTET STRING)
  *d++ = 0x04;
  *d++ = hashLen;
  if (PK11_HashBuf(SEC_OID_SHA1, d, issuerCert->derSubject.data,
                   issuerCert->derSubject.len) != SECSuccess) {
    return nullptr;
  }
  d += hashLen;

  // reqCert.issuerKeyHash (OCTET STRING)
  *d++ = 0x04;
  *d++ = hashLen;
  SECItem key = issuerCert->subjectPublicKeyInfo.subjectPublicKey;
  DER_ConvertBitString(&key);
  if (PK11_HashBuf(SEC_OID_SHA1, d, key.data, key.len) != SECSuccess) {
    return nullptr;
  }
  d += hashLen;

  // reqCert.serialNumber (INTEGER)
  *d++ = 0x02; // INTEGER
  *d++ = static_cast<uint8_t>(cert->serialNumber.len);
  for (size_t i = 0; i < cert->serialNumber.len; ++i) {
    *d++ = cert->serialNumber.data[i];
  }

  PR_ASSERT(d == encodedRequest->data + totalLen);

  return encodedRequest;
}
Beispiel #21
0
// BasicOCSPResponse       ::= SEQUENCE {
//    tbsResponseData      ResponseData,
//    signatureAlgorithm   AlgorithmIdentifier,
//    signature            BIT STRING,
//    certs            [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
der::Result
BasicResponse(der::Input& input, Context& context)
{
  der::Input::Mark mark(input.GetMark());

  uint16_t length;
  if (der::ExpectTagAndGetLength(input, der::SEQUENCE, length)
        != der::Success) {
    return der::Failure;
  }

  // The signature covers the entire DER encoding of tbsResponseData, including
  // the beginning tag and length. However, when we're parsing tbsResponseData,
  // we want to strip off the tag and length because we don't need it after
  // we've confirmed it's there and figured out what length it is.

  der::Input tbsResponseData;

  if (input.Skip(length, tbsResponseData) != der::Success) {
    return der::Failure;
  }

  CERTSignedData signedData;

  input.GetSECItem(siBuffer, mark, signedData.data);

  if (der::Nested(input, der::SEQUENCE,
                  bind(der::AlgorithmIdentifier, _1,
                       ref(signedData.signatureAlgorithm))) != der::Success) {
    return der::Failure;
  }

  if (der::Skip(input, der::BIT_STRING, signedData.signature) != der::Success) {
    return der::Failure;
  }
  if (signedData.signature.len == 0) {
    return der::Fail(SEC_ERROR_OCSP_BAD_SIGNATURE);
  }
  unsigned int unusedBitsAtEnd = signedData.signature.data[0];
  // XXX: Really the constraint should be that unusedBitsAtEnd must be less
  // than 7. But, we suspect there are no valid OCSP response signatures with
  // non-zero unused bits. It seems like NSS assumes this in various places, so
  // we enforce it. If we find compatibility issues, we'll know we're wrong.
  if (unusedBitsAtEnd != 0) {
    return der::Fail(SEC_ERROR_OCSP_BAD_SIGNATURE);
  }
  ++signedData.signature.data;
  --signedData.signature.len;
  signedData.signature.len = (signedData.signature.len << 3); // Bytes to bits

  // Parse certificates, if any

  SECItem certs[8];
  size_t numCerts = 0;

  if (!input.AtEnd()) {
    // We ignore the lengths of the wrappers because we'll detect bad lengths
    // during parsing--too short and we'll run out of input for parsing a cert,
    // and too long and we'll have leftover data that won't parse as a cert.

    // [0] wrapper
    if (der::ExpectTagAndIgnoreLength(
          input, der::CONSTRUCTED | der::CONTEXT_SPECIFIC | 0)
        != der::Success) {
      return der::Failure;
    }

    // SEQUENCE wrapper
    if (der::ExpectTagAndIgnoreLength(input, der::SEQUENCE) != der::Success) {
      return der::Failure;
    }

    // sequence of certificates
    while (!input.AtEnd()) {
      if (numCerts == PR_ARRAY_SIZE(certs)) {
        return der::Fail(SEC_ERROR_BAD_DER);
      }

      // Unwrap the SEQUENCE that contains the certificate, which is itself a
      // SEQUENCE.
      der::Input::Mark mark(input.GetMark());
      if (der::Skip(input, der::SEQUENCE) != der::Success) {
        return der::Failure;
      }

      input.GetSECItem(siBuffer, mark, certs[numCerts]);
      ++numCerts;
    }
  }

  return ResponseData(tbsResponseData, context, signedData, certs, numCerts);
}
Beispiel #22
0
/*
 * point validation is not necessary in general. But this checks a point (px)
 * against some known bad values.
 */
SECStatus
ec_Curve25519_pt_validate(const SECItem *px)
{
    PRUint8 *p;
    int i;
    PRUint8 forbiddenValues[12][32] = {
        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
        { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
        { 0xe0, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae,
          0x16, 0x56, 0xe3, 0xfa, 0xf1, 0x9f, 0xc4, 0x6a,
          0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32, 0xb1, 0xfd,
          0x86, 0x62, 0x05, 0x16, 0x5f, 0x49, 0xb8, 0x00 },
        { 0x5f, 0x9c, 0x95, 0xbc, 0xa3, 0x50, 0x8c, 0x24,
          0xb1, 0xd0, 0xb1, 0x55, 0x9c, 0x83, 0xef, 0x5b,
          0x04, 0x44, 0x5c, 0xc4, 0x58, 0x1c, 0x8e, 0x86,
          0xd8, 0x22, 0x4e, 0xdd, 0xd0, 0x9f, 0x11, 0x57 },
        { 0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
          0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
          0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
          0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f },
        { 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
          0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
          0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
          0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f },
        { 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
          0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
          0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
          0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f },
        { 0xcd, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae,
          0x16, 0x56, 0xe3, 0xfa, 0xf1, 0x9f, 0xc4, 0x6a,
          0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32, 0xb1, 0xfd,
          0x86, 0x62, 0x05, 0x16, 0x5f, 0x49, 0xb8, 0x80 },
        { 0x4c, 0x9c, 0x95, 0xbc, 0xa3, 0x50, 0x8c, 0x24,
          0xb1, 0xd0, 0xb1, 0x55, 0x9c, 0x83, 0xef, 0x5b,
          0x04, 0x44, 0x5c, 0xc4, 0x58, 0x1c, 0x8e, 0x86,
          0xd8, 0x22, 0x4e, 0xdd, 0xd0, 0x9f, 0x11, 0xd7 },
        { 0xd9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
          0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
          0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
          0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
        { 0xda, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
          0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
          0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
          0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
        { 0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
          0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
          0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
          0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
    };

    if (px->len == 32) {
        p = px->data;
    } else {
        return SECFailure;
    }

    for (i = 0; i < PR_ARRAY_SIZE(forbiddenValues); ++i) {
        if (NSS_SecureMemcmp(p, forbiddenValues[i], px->len) == 0) {
            return SECFailure;
        }
    }

    return SECSuccess;
}
Beispiel #23
0
SECKEYPrivateKey*
CryptoKey::PrivateKeyFromJwk(const JsonWebKey& aJwk,
                             const nsNSSShutDownPreventionLock& /*proofOfLock*/)
{
  if (!aJwk.mKty.WasPassed() || !aJwk.mKty.Value().EqualsLiteral(JWK_TYPE_RSA)) {
    return nullptr;
  }

  // Verify that all of the required parameters are present
  CryptoBuffer n, e, d, p, q, dp, dq, qi;
  if (!aJwk.mN.WasPassed() || NS_FAILED(n.FromJwkBase64(aJwk.mN.Value())) ||
      !aJwk.mE.WasPassed() || NS_FAILED(e.FromJwkBase64(aJwk.mE.Value())) ||
      !aJwk.mD.WasPassed() || NS_FAILED(d.FromJwkBase64(aJwk.mD.Value())) ||
      !aJwk.mP.WasPassed() || NS_FAILED(p.FromJwkBase64(aJwk.mP.Value())) ||
      !aJwk.mQ.WasPassed() || NS_FAILED(q.FromJwkBase64(aJwk.mQ.Value())) ||
      !aJwk.mDp.WasPassed() || NS_FAILED(dp.FromJwkBase64(aJwk.mDp.Value())) ||
      !aJwk.mDq.WasPassed() || NS_FAILED(dq.FromJwkBase64(aJwk.mDq.Value())) ||
      !aJwk.mQi.WasPassed() || NS_FAILED(qi.FromJwkBase64(aJwk.mQi.Value()))) {
    return nullptr;
  }

  // Compute the ID for this key
  // This is generated with a SHA-1 hash, so unlikely to collide
  ScopedSECItem nItem(n.ToSECItem());
  ScopedSECItem objID(PK11_MakeIDFromPubKey(nItem.get()));
  if (!nItem.get() || !objID.get()) {
    return nullptr;
  }

  // Populate template from parameters
  CK_OBJECT_CLASS privateKeyValue = CKO_PRIVATE_KEY;
  CK_KEY_TYPE rsaValue = CKK_RSA;
  CK_BBOOL falseValue = CK_FALSE;
  CK_ATTRIBUTE keyTemplate[14] = {
    { CKA_CLASS,            &privateKeyValue,      sizeof(privateKeyValue) },
    { CKA_KEY_TYPE,         &rsaValue,             sizeof(rsaValue) },
    { CKA_TOKEN,            &falseValue,           sizeof(falseValue) },
    { CKA_SENSITIVE,        &falseValue,           sizeof(falseValue) },
    { CKA_PRIVATE,          &falseValue,           sizeof(falseValue) },
    { CKA_ID,               objID->data,           objID->len },
    { CKA_MODULUS,          (void*) n.Elements(),  n.Length() },
    { CKA_PUBLIC_EXPONENT,  (void*) e.Elements(),  e.Length() },
    { CKA_PRIVATE_EXPONENT, (void*) d.Elements(),  d.Length() },
    { CKA_PRIME_1,          (void*) p.Elements(),  p.Length() },
    { CKA_PRIME_2,          (void*) q.Elements(),  q.Length() },
    { CKA_EXPONENT_1,       (void*) dp.Elements(), dp.Length() },
    { CKA_EXPONENT_2,       (void*) dq.Elements(), dq.Length() },
    { CKA_COEFFICIENT,      (void*) qi.Elements(), qi.Length() },
  };


  // Create a generic object with the contents of the key
  ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
  if (!slot.get()) {
    return nullptr;
  }

  ScopedPK11GenericObject obj(PK11_CreateGenericObject(slot.get(),
                                                       keyTemplate,
                                                       PR_ARRAY_SIZE(keyTemplate),
                                                       PR_FALSE));
  if (!obj.get()) {
    return nullptr;
  }

  // Have NSS translate the object to a private key by inspection
  // and make a copy we can own
  ScopedSECKEYPrivateKey privKey(PK11_FindKeyByKeyID(slot.get(), objID.get(),
                                                     nullptr));
  if (!privKey.get()) {
    return nullptr;
  }
  return SECKEY_CopyPrivateKey(privKey.get());
}
Beispiel #24
0
static SECStatus
ssl_UpdateSupportedGroups(sslSocket *ss, SECItem *data)
{
    PRInt32 list_len;
    unsigned int i;
    const sslNamedGroupDef *enabled[SSL_NAMED_GROUP_COUNT] = { 0 };
    PORT_Assert(SSL_NAMED_GROUP_COUNT == PR_ARRAY_SIZE(enabled));

    if (!data->data || data->len < 4) {
        (void)ssl3_DecodeError(ss);
        return SECFailure;
    }

    /* get the length of elliptic_curve_list */
    list_len = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
    if (list_len < 0 || data->len != list_len || (data->len % 2) != 0) {
        (void)ssl3_DecodeError(ss);
        return SECFailure;
    }

    /* disable all groups and remember the enabled groups */
    for (i = 0; i < SSL_NAMED_GROUP_COUNT; ++i) {
        enabled[i] = ss->namedGroupPreferences[i];
        ss->namedGroupPreferences[i] = NULL;
    }

    /* Read groups from data and enable if in |enabled| */
    while (data->len) {
        const sslNamedGroupDef *group;
        PRInt32 curve_name =
            ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
        if (curve_name < 0) {
            return SECFailure; /* fatal alert already sent */
        }
        group = ssl_LookupNamedGroup(curve_name);
        if (group) {
            for (i = 0; i < SSL_NAMED_GROUP_COUNT; ++i) {
                if (enabled[i] && group == enabled[i]) {
                    ss->namedGroupPreferences[i] = enabled[i];
                    break;
                }
            }
        }

        /* "Codepoints in the NamedCurve registry with a high byte of 0x01 (that
         * is, between 256 and 511 inclusive) are set aside for FFDHE groups,"
         * -- https://tools.ietf.org/html/draft-ietf-tls-negotiated-ff-dhe-10
         */
        if ((curve_name & 0xff00) == 0x0100) {
            ss->ssl3.hs.peerSupportsFfdheGroups = PR_TRUE;
        }
    }

    /* Note: if ss->opt.requireDHENamedGroups is set, we disable DHE cipher
     * suites, but we do that in ssl3_config_match(). */
    if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3 &&
        !ss->opt.requireDHENamedGroups && !ss->ssl3.hs.peerSupportsFfdheGroups) {
        /* If we don't require that DHE use named groups, and no FFDHE was
         * included, we pretend that they support all the FFDHE groups we do. */
        for (i = 0; i < SSL_NAMED_GROUP_COUNT; ++i) {
            if (enabled[i] && enabled[i]->keaType == ssl_kea_dh) {
                ss->namedGroupPreferences[i] = enabled[i];
            }
        }
    }

    return SECSuccess;
}
Beispiel #25
0
// We assume ext has been zero-initialized by its constructor and otherwise
// not modified.
//
// TODO(perf): This sorting of extensions should be be moved into the
// certificate decoder so that the results are cached with the certificate, so
// that the decoding doesn't have to happen more than once per cert.
Result
BackCert::Init(const SECItem& certDER)
{
  // XXX: Currently-known uses of mozilla::pkix create CERTCertificate objects
  // for all certs anyway, so the overhead of CERT_NewTempCertificate will be
  // reduced to a lookup in NSS's SECItem* -> CERTCertificate cache and
  // a CERT_DupCertificate. Eventually, we should parse the certificate using
  // mozilla::pkix::der and avoid the need to create a CERTCertificate at all.
  nssCert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
                                    const_cast<SECItem*>(&certDER),
                                    nullptr, false, true);
  if (!nssCert) {
    return MapSECStatus(SECFailure);
  }

  const CERTCertExtension* const* exts = nssCert->extensions;
  if (!exts) {
    return Success;
  }
  // We only decode v3 extensions for v3 certificates for two reasons.
  // 1. They make no sense in non-v3 certs
  // 2. An invalid cert can embed a basic constraints extension and the
  //    check basic constrains will asume that this is valid. Making it
  //    posible to create chains with v1 and v2 intermediates with is
  //    not desirable.
  if (! (nssCert->version.len == 1 &&
      nssCert->version.data[0] == mozilla::pkix::der::Version::v3)) {
    return Fail(RecoverableError, SEC_ERROR_EXTENSION_VALUE_INVALID);
  }

  const SECItem* dummyEncodedSubjectKeyIdentifier = nullptr;
  const SECItem* dummyEncodedAuthorityKeyIdentifier = nullptr;
  const SECItem* dummyEncodedAuthorityInfoAccess = nullptr;
  const SECItem* dummyEncodedSubjectAltName = nullptr;

  for (const CERTCertExtension* ext = *exts; ext; ext = *++exts) {
    const SECItem** out = nullptr;

    // python DottedOIDToCode.py id-ce 2.5.29
    static const uint8_t id_ce[] = {
      0x55, 0x1d
    };

    // python DottedOIDToCode.py id-pe-authorityInfoAccess 1.3.6.1.5.5.7.1.1
    static const uint8_t id_pe_authorityInfoAccess[] = {
      0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01
    };

    if (ext->id.len == PR_ARRAY_SIZE(id_ce) + 1 &&
        !memcmp(ext->id.data, id_ce, PR_ARRAY_SIZE(id_ce))) {
      switch (ext->id.data[ext->id.len - 1]) {
        case 14: out = &dummyEncodedSubjectKeyIdentifier; break; // bug 965136
        case 15: out = &encodedKeyUsage; break;
        case 17: out = &dummyEncodedSubjectAltName; break; // bug 970542
        case 19: out = &encodedBasicConstraints; break;
        case 30: out = &encodedNameConstraints; break;
        case 32: out = &encodedCertificatePolicies; break;
        case 35: out = &dummyEncodedAuthorityKeyIdentifier; break; // bug 965136
        case 37: out = &encodedExtendedKeyUsage; break;
        case 54: out = &encodedInhibitAnyPolicy; break; // Bug 989051
      }
    } else if (ext->id.len == PR_ARRAY_SIZE(id_pe_authorityInfoAccess) &&
               !memcmp(ext->id.data, id_pe_authorityInfoAccess,
                       PR_ARRAY_SIZE(id_pe_authorityInfoAccess))) {
      // We should remember the value of the encoded AIA extension here, but
      // since our TrustDomain implementations get the OCSP URI using
      // CERT_GetOCSPAuthorityInfoAccessLocation, we currently don't need to.
      out = &dummyEncodedAuthorityInfoAccess;
    }

    // If this is an extension we don't understand and it's marked critical,
    // we must reject this certificate.
    // (The only valid explicit value of the critical flag is TRUE because
    // it is defined as BOOLEAN DEFAULT FALSE, so we just assume it is true.)
    if (!out && ext->critical.data && ext->critical.len > 0) {
      return Fail(RecoverableError, SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION);
    }

    if (out) {
      // This is an extension we understand. Save it in results unless we've
      // already found the extension previously.
      if (*out) {
        // Duplicate extension
        return Fail(RecoverableError, SEC_ERROR_EXTENSION_VALUE_INVALID);
      }
      *out = &ext->value;
    }
  }

  return Success;
}
Beispiel #26
0
static PRStatus
IdentityInfoInit()
{
  for (size_t iEV = 0; iEV < PR_ARRAY_SIZE(myTrustedEVInfos); ++iEV) {
    nsMyTrustedEVInfo& entry = myTrustedEVInfos[iEV];

    SECStatus rv;
    CERTIssuerAndSN ias;

    rv = ATOB_ConvertAsciiToItem(&ias.derIssuer, const_cast<char*>(entry.issuer_base64));
    PR_ASSERT(rv == SECSuccess);
    if (rv != SECSuccess) {
      return PR_FAILURE;
    }
    rv = ATOB_ConvertAsciiToItem(&ias.serialNumber,
                                 const_cast<char*>(entry.serial_base64));
    PR_ASSERT(rv == SECSuccess);
    if (rv != SECSuccess) {
      SECITEM_FreeItem(&ias.derIssuer, false);
      return PR_FAILURE;
    }

    ias.serialNumber.type = siUnsignedInteger;

    entry.cert = CERT_FindCertByIssuerAndSN(nullptr, &ias);

    SECITEM_FreeItem(&ias.derIssuer, false);
    SECITEM_FreeItem(&ias.serialNumber, false);

    // If an entry is missing in the NSS root database, it may be because the
    // root database is out of sync with what we expect (e.g. a different
    // version of system NSS is installed). We will just silently avoid
    // treating that root cert as EV.
    if (!entry.cert) {
#ifdef DEBUG
      // The debug CA info is at position 0, and is NOT on the NSS root db
      if (iEV == 0) {
        continue;
      }
#endif
      PR_NOT_REACHED("Could not find EV root in NSS storage");
      continue;
    }

    unsigned char certFingerprint[20];
    rv = PK11_HashBuf(SEC_OID_SHA1, certFingerprint,
                      entry.cert->derCert.data, entry.cert->derCert.len);
    PR_ASSERT(rv == SECSuccess);
    if (rv == SECSuccess) {
      bool same = !memcmp(certFingerprint, entry.ev_root_sha1_fingerprint, 20);
      PR_ASSERT(same);
      if (same) {

        SECItem ev_oid_item;
        ev_oid_item.data = nullptr;
        ev_oid_item.len = 0;
        rv = SEC_StringToOID(nullptr, &ev_oid_item, entry.dotted_oid, 0);
        PR_ASSERT(rv == SECSuccess);
        if (rv == SECSuccess) {
          entry.oid_tag = register_oid(&ev_oid_item, entry.oid_name);
          if (entry.oid_tag == SEC_OID_UNKNOWN) {
            rv = SECFailure;
          }
          SECITEM_FreeItem(&ev_oid_item, false);
        }
      } else {
        PR_SetError(SEC_ERROR_BAD_DATA, 0);
        rv = SECFailure;
      }
    }

    if (rv != SECSuccess) {
      CERT_DestroyCertificate(entry.cert);
      entry.cert = nullptr;
      entry.oid_tag = SEC_OID_UNKNOWN;
      return PR_FAILURE;
    }
  }

  return PR_SUCCESS;
}
Beispiel #27
0
// NSS exports private EC keys without the CKA_EC_POINT attribute, i.e. the
// public value. To properly export the private key to JWK or PKCS #8 we need
// the public key data though and so we use this method to augment a private
// key with data from the given public key.
nsresult
CryptoKey::AddPublicKeyData(SECKEYPublicKey* aPublicKey)
{
  // This should be a private key.
  MOZ_ASSERT(GetKeyType() == PRIVATE);
  // There should be a private NSS key with type 'EC'.
  MOZ_ASSERT(mPrivateKey && mPrivateKey->keyType == ecKey);
  // The given public key should have the same key type.
  MOZ_ASSERT(aPublicKey->keyType == mPrivateKey->keyType);

  nsNSSShutDownPreventionLock locker;

  ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
  if (!slot) {
    return NS_ERROR_DOM_OPERATION_ERR;
  }

  // Generate a random 160-bit object ID.
  ScopedSECItem objID(::SECITEM_AllocItem(nullptr, nullptr, 20));
  SECStatus rv = PK11_GenerateRandomOnSlot(slot, objID->data, objID->len);
  if (rv != SECSuccess) {
    return NS_ERROR_DOM_OPERATION_ERR;
  }

  // Read EC params.
  ScopedSECItem params(::SECITEM_AllocItem(nullptr, nullptr, 0));
  rv = PK11_ReadRawAttribute(PK11_TypePrivKey, mPrivateKey, CKA_EC_PARAMS,
                             params);
  if (rv != SECSuccess) {
    return NS_ERROR_DOM_OPERATION_ERR;
  }

  // Read private value.
  ScopedSECItem value(::SECITEM_AllocItem(nullptr, nullptr, 0));
  rv = PK11_ReadRawAttribute(PK11_TypePrivKey, mPrivateKey, CKA_VALUE, value);
  if (rv != SECSuccess) {
    return NS_ERROR_DOM_OPERATION_ERR;
  }

  SECItem* point = &aPublicKey->u.ec.publicValue;
  CK_OBJECT_CLASS privateKeyValue = CKO_PRIVATE_KEY;
  CK_BBOOL falseValue = CK_FALSE;
  CK_KEY_TYPE ecValue = CKK_EC;

  CK_ATTRIBUTE keyTemplate[9] = {
    { CKA_CLASS,            &privateKeyValue,     sizeof(privateKeyValue) },
    { CKA_KEY_TYPE,         &ecValue,             sizeof(ecValue) },
    { CKA_TOKEN,            &falseValue,          sizeof(falseValue) },
    { CKA_SENSITIVE,        &falseValue,          sizeof(falseValue) },
    { CKA_PRIVATE,          &falseValue,          sizeof(falseValue) },
    { CKA_ID,               objID->data,          objID->len },
    { CKA_EC_PARAMS,        params->data,         params->len },
    { CKA_EC_POINT,         point->data,          point->len },
    { CKA_VALUE,            value->data,          value->len },
  };

  mPrivateKey = PrivateKeyFromPrivateKeyTemplate(objID, keyTemplate,
                                                 PR_ARRAY_SIZE(keyTemplate));
  NS_ENSURE_TRUE(mPrivateKey, NS_ERROR_DOM_OPERATION_ERR);

  return NS_OK;
}
Beispiel #28
0
static SECStatus applyCryptoPolicy(char *policy)
{
    char *s, *sp, *p;
    unsigned i;
    SECStatus rv;
    unsigned unknown;

    if (policy == NULL || policy[0] == 0) {
        return SECSuccess;      /* do nothing */
    }

    p = policy;

    /* disable all options by default */
    for (i = 0; i < PR_ARRAY_SIZE(algOptList); i++) {
        NSS_SetAlgorithmPolicy(algOptList[i].oid, 0, algOptList[i].val);
    }

    NSS_SetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, NSS_USE_POLICY_IN_SSL, 0);

    do {
        s = strtok_r(p, ":", &sp);
        p = NULL;

        if (s != NULL) {
            unknown = 1;

            for (i = 0; i < PR_ARRAY_SIZE(algOptList); i++) {
                if (strcasecmp(algOptList[i].name, s) == 0) {
                    rv = NSS_SetAlgorithmPolicy(algOptList[i].oid,
                                                algOptList[i].val, 0);
                    if (rv != SECSuccess) {
                        /* could not enable option */
                        rv = SECFailure;
                        goto cleanup;
                    }
                    unknown = 0;
                    break;
                }
            }

            if (unknown != 0) {
                for (i = 0; i < PR_ARRAY_SIZE(freeOptList); i++) {
	            if (strncasecmp(freeOptList[i].name, s, freeOptList[i].name_size) == 0 &&
	            	s[freeOptList[i].name_size] == '=') {
	            	PRInt32 val = atoi(&s[freeOptList[i].name_size+1]);
	            	assert(val != 0);

                        rv = NSS_OptionSet(freeOptList[i].option, val);
	                if (rv != SECSuccess) {
                            /* could not enable option */
                            rv = SECFailure;
                            goto cleanup;
                        }
                        unknown = 0;
                        break;
	            }
                }
            }

            if (unknown != 0) {
                fprintf(stderr, "error in term '%s'\n", s);
                rv = SECFailure;
                goto cleanup;
            }
        }
    } while (s != NULL);

  cleanup:
    /*NSS cannot recover*/
    rv = SECSuccess;
    return rv;
}