mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-20 23:37:33 +09:00
Replace NSS with Pale Moon's
This commit is contained in:
parent
ff1e5e48bf
commit
8c2e376f94
2870 changed files with 1762232 additions and 1374220 deletions
|
|
@ -17,6 +17,7 @@
|
|||
'include/pkix/Time.h',
|
||||
'include/pkix/Result.h',
|
||||
'include/pkix/pkix.h',
|
||||
'include/pkix/pkixc.h',
|
||||
'include/pkix/pkixnss.h',
|
||||
'include/pkix/pkixtypes.h',
|
||||
'include/pkix/pkixutil.h',
|
||||
|
|
@ -44,4 +45,4 @@
|
|||
'variables': {
|
||||
'module': 'nss'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This code is made available to you under your choice of the following sets
|
||||
* of licensing terms:
|
||||
*/
|
||||
|
|
@ -41,7 +42,7 @@ TestKeyPair* CreateTestKeyPair(const TestPublicKeyAlgorithm publicKeyAlg,
|
|||
const ScopedSECKEYPublicKey& publicKey,
|
||||
const ScopedSECKEYPrivateKey& privateKey);
|
||||
}
|
||||
}
|
||||
} // namespace mozilla::pkix::test
|
||||
} // namespace pkix
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_pkix_test_pkixtestnss_h
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This code is made available to you under your choice of the following sets
|
||||
* of licensing terms:
|
||||
*/
|
||||
|
|
@ -302,10 +303,11 @@ TestKeyPair* GenerateDSSKeyPair();
|
|||
inline void DeleteTestKeyPair(TestKeyPair* keyPair) { delete keyPair; }
|
||||
typedef std::unique_ptr<TestKeyPair> ScopedTestKeyPair;
|
||||
|
||||
Result TestVerifyECDSASignedDigest(const SignedDigest& signedDigest,
|
||||
Input subjectPublicKeyInfo);
|
||||
Result TestVerifyRSAPKCS1SignedDigest(const SignedDigest& signedDigest,
|
||||
Input subjectPublicKeyInfo);
|
||||
Result TestVerifyECDSASignedData(Input data, DigestAlgorithm digestAlgorithm,
|
||||
Input signature, Input subjectPublicKeyInfo);
|
||||
Result TestVerifyRSAPKCS1SignedData(Input data, DigestAlgorithm digestAlgorithm,
|
||||
Input signature,
|
||||
Input subjectPublicKeyInfo);
|
||||
Result TestDigestBuf(Input item, DigestAlgorithm digestAlg,
|
||||
/*out*/ uint8_t* digestBuf, size_t digestBufLen);
|
||||
|
||||
|
|
@ -430,8 +432,8 @@ class OCSPResponseContext final {
|
|||
};
|
||||
|
||||
ByteString CreateEncodedOCSPResponse(OCSPResponseContext& context);
|
||||
}
|
||||
}
|
||||
} // namespace mozilla::pkix::test
|
||||
} // namespace test
|
||||
} // namespace pkix
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_pkix_test_pkixtestutil_h
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This code is made available to you under your choice of the following sets
|
||||
* of licensing terms:
|
||||
*/
|
||||
|
|
@ -303,7 +304,7 @@ inline bool InputContains(const Input& input, uint8_t toFind) {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace mozilla::pkix
|
||||
} // namespace pkix
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_pkix_Input_h
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This code is made available to you under your choice of the following sets
|
||||
* of licensing terms:
|
||||
*/
|
||||
|
|
@ -187,7 +188,7 @@ static const unsigned int FATAL_ERROR_FLAG = 0x800;
|
|||
SEC_ERROR_LIBRARY_FAILURE) \
|
||||
MOZILLA_PKIX_MAP(FATAL_ERROR_NO_MEMORY, FATAL_ERROR_FLAG | 4, \
|
||||
SEC_ERROR_NO_MEMORY) \
|
||||
/* nothing here */
|
||||
/* nothing here */
|
||||
|
||||
enum class Result {
|
||||
#define MOZILLA_PKIX_MAP(name, value, nss_name) name = value,
|
||||
|
|
@ -212,7 +213,7 @@ inline Result NotReached(const char* /*explanation*/, Result result) {
|
|||
assert(false);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
} // namespace mozilla::pkix
|
||||
} // namespace pkix
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_pkix_Result_h
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This code is made available to you under your choice of the following sets
|
||||
* of licensing terms:
|
||||
*/
|
||||
|
|
@ -110,6 +111,9 @@ Time Now();
|
|||
// Note the epoch is the unix epoch (ie 00:00:00 UTC, 1 January 1970)
|
||||
Time TimeFromEpochInSeconds(uint64_t secondsSinceEpoch);
|
||||
|
||||
// Note the epoch is the unix epoch (ie 00:00:00 UTC, 1 January 1970)
|
||||
Result SecondsSinceEpochFromTime(Time time, uint64_t* outSeconds);
|
||||
|
||||
class Duration final {
|
||||
public:
|
||||
Duration(Time timeA, Time timeB)
|
||||
|
|
@ -128,9 +132,11 @@ class Duration final {
|
|||
}
|
||||
|
||||
private:
|
||||
friend Result SecondsSinceEpochFromTime(Time time, uint64_t* outSeconds);
|
||||
|
||||
uint64_t durationInSeconds;
|
||||
};
|
||||
}
|
||||
} // namespace mozilla::pkix
|
||||
} // namespace pkix
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_pkix_Time_h
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This code is made available to you under your choice of the following sets
|
||||
* of licensing terms:
|
||||
*/
|
||||
|
|
@ -116,6 +117,8 @@ Result BuildCertChain(TrustDomain& trustDomain, Input cert, Time time,
|
|||
// - IP addresses are out of scope of RFC 6125, but this method accepts them for
|
||||
// backward compatibility (see SearchNames in pkixnames.cpp)
|
||||
// - A wildcard in a DNS-ID may only appear as the entirety of the first label.
|
||||
// If the NameMatchingPolicy is omitted, a StrictNameMatchingPolicy is used.
|
||||
Result CheckCertHostname(Input cert, Input hostname);
|
||||
Result CheckCertHostname(Input cert, Input hostname,
|
||||
NameMatchingPolicy& nameMatchingPolicy);
|
||||
|
||||
|
|
@ -153,7 +156,7 @@ Result VerifyEncodedOCSPResponse(
|
|||
// requirement for another value. Empty extensions are also rejected.
|
||||
Result CheckTLSFeaturesAreSatisfied(Input& cert,
|
||||
const Input* stapledOCSPResponse);
|
||||
}
|
||||
} // namespace mozilla::pkix
|
||||
} // namespace pkix
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_pkix_pkix_h
|
||||
|
|
|
|||
47
security/nss/lib/mozpkix/include/pkix/pkixc.h
Normal file
47
security/nss/lib/mozpkix/include/pkix/pkixc.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#ifndef mozilla_pkix_pkixc_h
|
||||
#define mozilla_pkix_pkixc_h
|
||||
|
||||
#include "prerror.h"
|
||||
#include "stdint.h"
|
||||
|
||||
// VerifyCertificateChain will attempt to build a verified certificate chain
|
||||
// starting from the 0th certificate in the given array to the indicated trust
|
||||
// anchor. It returns true on success and false otherwise. No particular key
|
||||
// usage is required, and no particular policy is required. The code signing
|
||||
// extended key usage is required. No revocation checking is performed. RSA
|
||||
// keys must be at least 2048 bits long, and EC keys must be from one of the
|
||||
// curves secp256r1, secp384r1, or secp521r1. Only SHA256, SHA384, and SHA512
|
||||
// are acceptable digest algorithms. When doing name checking, the subject
|
||||
// common name field is ignored. At least one certificate must be provided.
|
||||
// certificate is an array of pointers to certificates.
|
||||
// certificateLengths is an array of the lengths of each certificate.
|
||||
// numCertificates indicates how many certificates are in certificates.
|
||||
// secondsSinceEpoch indicates the time at which the certificate chain must be
|
||||
// valid, in seconds since the epoch.
|
||||
// rootSHA256Hash identifies a trust anchor by the SHA256 hash of its contents.
|
||||
// It must be an array of 32 bytes.
|
||||
// hostname is a doman name for which the end-entity certificate must be valid.
|
||||
// error will be set if and only if the return value is false. Its value may
|
||||
// indicate why verification failed.
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
bool VerifyCodeSigningCertificateChain(const uint8_t** certificates,
|
||||
const uint16_t* certificateLengths,
|
||||
size_t numCertificates,
|
||||
uint64_t secondsSinceEpoch,
|
||||
const uint8_t* rootSHA256Hash,
|
||||
const uint8_t* hostname,
|
||||
size_t hostnameLength,
|
||||
/* out */ PRErrorCode* error);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // mozilla_pkix_pkixc_h
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This code is made available to you under your choice of the following sets
|
||||
* of licensing terms:
|
||||
*/
|
||||
|
|
@ -58,7 +59,7 @@ Result CheckValidity(Time time, Time notBefore, Time notAfter);
|
|||
// Check that a subject has TLS Feature (rfc7633) requirements that match its
|
||||
// potential issuer
|
||||
Result CheckTLSFeatures(const BackCert& subject, BackCert& potentialIssuer);
|
||||
}
|
||||
} // namespace mozilla::pkix
|
||||
} // namespace pkix
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_pkix_pkixcheck_h
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This code is made available to you under your choice of the following sets
|
||||
* of licensing terms:
|
||||
*/
|
||||
|
|
@ -487,7 +488,7 @@ inline Result OptionalExtensions(Reader& input, uint8_t tag,
|
|||
Result DigestAlgorithmIdentifier(Reader& input,
|
||||
/*out*/ DigestAlgorithm& algorithm);
|
||||
|
||||
enum class PublicKeyAlgorithm { RSA_PKCS1, ECDSA, Uninitialized };
|
||||
enum class PublicKeyAlgorithm { RSA_PKCS1, RSA_PSS, ECDSA };
|
||||
|
||||
Result SignatureAlgorithmIdentifierValue(
|
||||
Reader& input,
|
||||
|
|
@ -523,8 +524,11 @@ struct SignedDataWithSignature final {
|
|||
// certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
|
||||
Result SignedData(Reader& input, /*out*/ Reader& tbs,
|
||||
/*out*/ SignedDataWithSignature& signedDataWithSignature);
|
||||
}
|
||||
}
|
||||
} // namespace mozilla::pkix::der
|
||||
|
||||
// Parses an ECDSASigValue (RFC 5480) into its components r and s.
|
||||
Result ECDSASigValue(Input ecdsaSignature, /*out*/ Input& r, /*out*/ Input& s);
|
||||
} // namespace der
|
||||
} // namespace pkix
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_pkix_pkixder_h
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This code is made available to you under your choice of the following sets
|
||||
* of licensing terms:
|
||||
*/
|
||||
|
|
@ -33,15 +34,21 @@ namespace pkix {
|
|||
|
||||
// Verifies the PKCS#1.5 signature on the given data using the given RSA public
|
||||
// key.
|
||||
Result VerifyRSAPKCS1SignedDigestNSS(const SignedDigest& sd,
|
||||
Input subjectPublicKeyInfo,
|
||||
void* pkcs11PinArg);
|
||||
Result VerifyRSAPKCS1SignedDataNSS(Input data, DigestAlgorithm digestAlgorithm,
|
||||
Input signature, Input subjectPublicKeyInfo,
|
||||
void* pkcs11PinArg);
|
||||
|
||||
// Verifies the RSA-PSS signature on the given data using the given RSA
|
||||
// public key.
|
||||
Result VerifyRSAPSSSignedDataNSS(Input data, DigestAlgorithm digestAlgorithm,
|
||||
Input signature, Input subjectPublicKeyInfo,
|
||||
void* pkcs11PinArg);
|
||||
|
||||
// Verifies the ECDSA signature on the given data using the given ECC public
|
||||
// key.
|
||||
Result VerifyECDSASignedDigestNSS(const SignedDigest& sd,
|
||||
Input subjectPublicKeyInfo,
|
||||
void* pkcs11PinArg);
|
||||
Result VerifyECDSASignedDataNSS(Input data, DigestAlgorithm digestAlgorithm,
|
||||
Input signature, Input subjectPublicKeyInfo,
|
||||
void* pkcs11PinArg);
|
||||
|
||||
// Computes the digest of the given data using the given digest algorithm.
|
||||
//
|
||||
|
|
@ -99,7 +106,7 @@ inline SECItem UnsafeMapInputToSECItem(Input input) {
|
|||
"input.GetLength() must fit in a SECItem");
|
||||
return result;
|
||||
}
|
||||
}
|
||||
} // namespace mozilla::pkix
|
||||
} // namespace pkix
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_pkix_pkixnss_h
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This code is made available to you under your choice of the following sets
|
||||
* of licensing terms:
|
||||
*/
|
||||
|
|
@ -51,14 +52,6 @@ enum class NamedCurve {
|
|||
secp256r1 = 3,
|
||||
};
|
||||
|
||||
struct SignedDigest final {
|
||||
Input digest;
|
||||
DigestAlgorithm digestAlgorithm;
|
||||
Input signature;
|
||||
|
||||
void operator=(const SignedDigest&) = delete;
|
||||
};
|
||||
|
||||
enum class EndEntityOrCA { MustBeEndEntity = 0, MustBeCA = 1 };
|
||||
|
||||
enum class KeyUsage : uint8_t {
|
||||
|
|
@ -277,10 +270,10 @@ class TrustDomain {
|
|||
|
||||
virtual Result CheckRevocation(EndEntityOrCA endEntityOrCA,
|
||||
const CertID& certID, Time time,
|
||||
Time validityBeginning,
|
||||
Duration validityDuration,
|
||||
/*optional*/ const Input* stapledOCSPresponse,
|
||||
/*optional*/ const Input* aiaExtension) = 0;
|
||||
/*optional*/ const Input* aiaExtension,
|
||||
/*optional*/ const Input* sctExtension) = 0;
|
||||
|
||||
// Check that the given digest algorithm is acceptable for use in signatures.
|
||||
//
|
||||
|
|
@ -304,10 +297,22 @@ class TrustDomain {
|
|||
//
|
||||
// CheckRSAPublicKeyModulusSizeInBits will be called before calling this
|
||||
// function, so it is not necessary to repeat those checks here. However,
|
||||
// VerifyRSAPKCS1SignedDigest *is* responsible for doing the mathematical
|
||||
// VerifyRSAPKCS1SignedData *is* responsible for doing the mathematical
|
||||
// verification of the public key validity as specified in NIST SP 800-56A.
|
||||
virtual Result VerifyRSAPKCS1SignedDigest(const SignedDigest& signedDigest,
|
||||
Input subjectPublicKeyInfo) = 0;
|
||||
virtual Result VerifyRSAPKCS1SignedData(Input data,
|
||||
DigestAlgorithm digestAlgorithm,
|
||||
Input signature,
|
||||
Input subjectPublicKeyInfo) = 0;
|
||||
|
||||
// Verify the given RSA-PSS signature on the given digest using the
|
||||
// given RSA public key.
|
||||
//
|
||||
// CheckRSAPublicKeyModulusSizeInBits will be called before calling this
|
||||
// function, so it is not necessary to repeat those checks here.
|
||||
virtual Result VerifyRSAPSSSignedData(Input data,
|
||||
DigestAlgorithm digestAlgorithm,
|
||||
Input signature,
|
||||
Input subjectPublicKeyInfo) = 0;
|
||||
|
||||
// Check that the given named ECC curve is acceptable for ECDSA signatures.
|
||||
//
|
||||
|
|
@ -322,10 +327,12 @@ class TrustDomain {
|
|||
//
|
||||
// CheckECDSACurveIsAcceptable will be called before calling this function,
|
||||
// so it is not necessary to repeat that check here. However,
|
||||
// VerifyECDSASignedDigest *is* responsible for doing the mathematical
|
||||
// VerifyECDSASignedData *is* responsible for doing the mathematical
|
||||
// verification of the public key validity as specified in NIST SP 800-56A.
|
||||
virtual Result VerifyECDSASignedDigest(const SignedDigest& signedDigest,
|
||||
Input subjectPublicKeyInfo) = 0;
|
||||
virtual Result VerifyECDSASignedData(Input data,
|
||||
DigestAlgorithm digestAlgorithm,
|
||||
Input signature,
|
||||
Input subjectPublicKeyInfo) = 0;
|
||||
|
||||
// Check that the validity duration is acceptable.
|
||||
//
|
||||
|
|
@ -394,7 +401,14 @@ class NameMatchingPolicy {
|
|||
NameMatchingPolicy(const NameMatchingPolicy&) = delete;
|
||||
void operator=(const NameMatchingPolicy&) = delete;
|
||||
};
|
||||
}
|
||||
} // namespace mozilla::pkix
|
||||
|
||||
class StrictNameMatchingPolicy : public NameMatchingPolicy {
|
||||
public:
|
||||
virtual Result FallBackToCommonName(
|
||||
Time notBefore,
|
||||
/*out*/ FallBackToSearchWithinSubject& fallBacktoCommonName) override;
|
||||
};
|
||||
} // namespace pkix
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_pkix_pkixtypes_h
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This code is made available to you under your choice of the following sets
|
||||
* of licensing terms:
|
||||
*/
|
||||
|
|
@ -191,18 +192,6 @@ inline unsigned int DaysBeforeYear(unsigned int year) {
|
|||
|
||||
static const size_t MAX_DIGEST_SIZE_IN_BYTES = 512 / 8; // sha-512
|
||||
|
||||
Result DigestSignedData(TrustDomain& trustDomain,
|
||||
const der::SignedDataWithSignature& signedData,
|
||||
/*out*/ uint8_t (&digestBuf)[MAX_DIGEST_SIZE_IN_BYTES],
|
||||
/*out*/ der::PublicKeyAlgorithm& publicKeyAlg,
|
||||
/*out*/ SignedDigest& signedDigest);
|
||||
|
||||
Result VerifySignedDigest(TrustDomain& trustDomain,
|
||||
der::PublicKeyAlgorithm publicKeyAlg,
|
||||
const SignedDigest& signedDigest,
|
||||
Input signerSubjectPublicKeyInfo);
|
||||
|
||||
// Combines DigestSignedData and VerifySignedDigest
|
||||
Result VerifySignedData(TrustDomain& trustDomain,
|
||||
const der::SignedDataWithSignature& signedData,
|
||||
Input signerSubjectPublicKeyInfo);
|
||||
|
|
@ -272,7 +261,7 @@ inline size_t DigestAlgorithmToSizeInBytes(DigestAlgorithm digestAlgorithm) {
|
|||
MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace mozilla::pkix
|
||||
} // namespace pkix
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_pkix_pkixutil_h
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This code is made available to you under your choice of the following sets
|
||||
* of licensing terms:
|
||||
*/
|
||||
|
|
@ -60,7 +61,6 @@ public:
|
|||
, stapledOCSPResponse(aStapledOCSPResponse)
|
||||
, subCACount(aSubCACount)
|
||||
, deferredSubjectError(aDeferredSubjectError)
|
||||
, subjectSignaturePublicKeyAlg(der::PublicKeyAlgorithm::Uninitialized)
|
||||
, result(Result::FATAL_ERROR_LIBRARY_FAILURE)
|
||||
, resultWasSet(false)
|
||||
, buildForwardCallBudget(aBuildForwardCallBudget)
|
||||
|
|
@ -83,11 +83,6 @@ private:
|
|||
const unsigned int subCACount;
|
||||
const Result deferredSubjectError;
|
||||
|
||||
// Initialized lazily.
|
||||
uint8_t subjectSignatureDigestBuf[MAX_DIGEST_SIZE_IN_BYTES];
|
||||
der::PublicKeyAlgorithm subjectSignaturePublicKeyAlg;
|
||||
SignedDigest subjectSignature;
|
||||
|
||||
Result RecordResult(Result currentResult, /*out*/ bool& keepGoing);
|
||||
Result result;
|
||||
bool resultWasSet;
|
||||
|
|
@ -214,22 +209,8 @@ PathBuildingStep::Check(Input potentialIssuerDER,
|
|||
return RecordResult(rv, keepGoing);
|
||||
}
|
||||
|
||||
// Calculate the digest of the subject's signed data if we haven't already
|
||||
// done so. We do this lazily to avoid doing it at all if we backtrack before
|
||||
// getting to this point. We cache the result to avoid recalculating it if we
|
||||
// backtrack after getting to this point.
|
||||
if (subjectSignature.digest.GetLength() == 0) {
|
||||
rv = DigestSignedData(trustDomain, subject.GetSignedData(),
|
||||
subjectSignatureDigestBuf,
|
||||
subjectSignaturePublicKeyAlg, subjectSignature);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
rv = VerifySignedDigest(trustDomain, subjectSignaturePublicKeyAlg,
|
||||
subjectSignature,
|
||||
potentialIssuer.GetSubjectPublicKeyInfo());
|
||||
rv = VerifySignedData(trustDomain, subject.GetSignedData(),
|
||||
potentialIssuer.GetSubjectPublicKeyInfo());
|
||||
if (rv != Success) {
|
||||
return RecordResult(rv, keepGoing);
|
||||
}
|
||||
|
|
@ -251,9 +232,9 @@ PathBuildingStep::Check(Input potentialIssuerDER,
|
|||
}
|
||||
Duration validityDuration(notAfter, notBefore);
|
||||
rv = trustDomain.CheckRevocation(subject.endEntityOrCA, certID, time,
|
||||
notBefore, validityDuration,
|
||||
stapledOCSPResponse,
|
||||
subject.GetAuthorityInfoAccess());
|
||||
validityDuration, stapledOCSPResponse,
|
||||
subject.GetAuthorityInfoAccess(),
|
||||
subject.GetSignedCertificateTimestamps());
|
||||
if (rv != Success) {
|
||||
// Since this is actually a problem with the current subject certificate
|
||||
// (rather than the issuer), it doesn't make sense to keep going; all
|
||||
|
|
|
|||
228
security/nss/lib/mozpkix/lib/pkixc.cpp
Normal file
228
security/nss/lib/mozpkix/lib/pkixc.cpp
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "mozpkix/pkixc.h"
|
||||
|
||||
#include "mozpkix/pkix.h"
|
||||
#include "mozpkix/pkixnss.h"
|
||||
#include "mozpkix/pkixtypes.h"
|
||||
#include "secerr.h"
|
||||
|
||||
using namespace mozilla::pkix;
|
||||
|
||||
const size_t SHA256_DIGEST_LENGTH = 256 / 8;
|
||||
|
||||
class CodeSigningTrustDomain final : public TrustDomain {
|
||||
public:
|
||||
explicit CodeSigningTrustDomain(const uint8_t** certificates,
|
||||
const uint16_t* certificateLengths,
|
||||
size_t numCertificates,
|
||||
const uint8_t* rootSHA256Digest)
|
||||
: mCertificates(certificates),
|
||||
mCertificateLengths(certificateLengths),
|
||||
mNumCertificates(numCertificates),
|
||||
mRootSHA256Digest(rootSHA256Digest) {}
|
||||
|
||||
virtual Result GetCertTrust(EndEntityOrCA endEntityOrCA,
|
||||
const CertPolicyId& policy,
|
||||
Input candidateCertDER,
|
||||
/*out*/ TrustLevel& trustLevel) override {
|
||||
uint8_t digestBuf[SHA256_DIGEST_LENGTH] = {0};
|
||||
Result rv = DigestBufNSS(candidateCertDER, DigestAlgorithm::sha256,
|
||||
digestBuf, SHA256_DIGEST_LENGTH);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
Input candidateDigestInput;
|
||||
rv = candidateDigestInput.Init(digestBuf, SHA256_DIGEST_LENGTH);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
Input rootDigestInput;
|
||||
rv = rootDigestInput.Init(mRootSHA256Digest, SHA256_DIGEST_LENGTH);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
if (InputsAreEqual(candidateDigestInput, rootDigestInput)) {
|
||||
trustLevel = TrustLevel::TrustAnchor;
|
||||
} else {
|
||||
trustLevel = TrustLevel::InheritsTrust;
|
||||
}
|
||||
return Success;
|
||||
}
|
||||
|
||||
virtual Result FindIssuer(Input encodedIssuerName, IssuerChecker& checker,
|
||||
Time time) override {
|
||||
for (size_t i = 0; i < mNumCertificates; i++) {
|
||||
Input certInput;
|
||||
Result rv = certInput.Init(mCertificates[i], mCertificateLengths[i]);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
bool keepGoing;
|
||||
rv = checker.Check(certInput, nullptr /*additionalNameConstraints*/,
|
||||
keepGoing);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
if (!keepGoing) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return Success;
|
||||
}
|
||||
|
||||
virtual Result CheckRevocation(
|
||||
EndEntityOrCA endEntityOrCA, const CertID& certID, Time time,
|
||||
Duration validityDuration,
|
||||
/*optional*/ const Input* stapledOCSPresponse,
|
||||
/*optional*/ const Input* aiaExtension,
|
||||
/*optional*/ const Input* sctExtension) override {
|
||||
return Success;
|
||||
}
|
||||
|
||||
virtual Result IsChainValid(const DERArray& certChain, Time time,
|
||||
const CertPolicyId& requiredPolicy) override {
|
||||
return Success;
|
||||
}
|
||||
|
||||
virtual Result CheckSignatureDigestAlgorithm(DigestAlgorithm digestAlg,
|
||||
EndEntityOrCA endEntityOrCA,
|
||||
Time notBefore) override {
|
||||
switch (digestAlg) {
|
||||
case DigestAlgorithm::sha256: // fall through
|
||||
case DigestAlgorithm::sha384: // fall through
|
||||
case DigestAlgorithm::sha512:
|
||||
return Success;
|
||||
default:
|
||||
return Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED;
|
||||
}
|
||||
}
|
||||
|
||||
virtual Result CheckRSAPublicKeyModulusSizeInBits(
|
||||
EndEntityOrCA endEntityOrCA, unsigned int modulusSizeInBits) override {
|
||||
if (modulusSizeInBits < 2048) {
|
||||
return Result::ERROR_INADEQUATE_KEY_SIZE;
|
||||
}
|
||||
return Success;
|
||||
}
|
||||
|
||||
virtual Result VerifyRSAPKCS1SignedData(
|
||||
Input data, DigestAlgorithm digestAlgorithm, Input signature,
|
||||
Input subjectPublicKeyInfo) override {
|
||||
return VerifyRSAPKCS1SignedDataNSS(data, digestAlgorithm, signature,
|
||||
subjectPublicKeyInfo, nullptr);
|
||||
}
|
||||
|
||||
virtual Result VerifyRSAPSSSignedData(
|
||||
Input data, DigestAlgorithm digestAlgorithm, Input signature,
|
||||
Input subjectPublicKeyInfo) override {
|
||||
return VerifyRSAPSSSignedDataNSS(data, digestAlgorithm, signature,
|
||||
subjectPublicKeyInfo, nullptr);
|
||||
}
|
||||
|
||||
virtual Result CheckECDSACurveIsAcceptable(EndEntityOrCA endEntityOrCA,
|
||||
NamedCurve curve) override {
|
||||
switch (curve) {
|
||||
case NamedCurve::secp256r1: // fall through
|
||||
case NamedCurve::secp384r1: // fall through
|
||||
case NamedCurve::secp521r1:
|
||||
return Success;
|
||||
}
|
||||
|
||||
return Result::ERROR_UNSUPPORTED_ELLIPTIC_CURVE;
|
||||
}
|
||||
|
||||
virtual Result VerifyECDSASignedData(
|
||||
Input data, DigestAlgorithm digestAlgorithm, Input signature,
|
||||
Input subjectPublicKeyInfo) override {
|
||||
return VerifyECDSASignedDataNSS(data, digestAlgorithm, signature,
|
||||
subjectPublicKeyInfo, nullptr);
|
||||
}
|
||||
|
||||
virtual Result CheckValidityIsAcceptable(Time notBefore, Time notAfter,
|
||||
EndEntityOrCA endEntityOrCA,
|
||||
KeyPurposeId keyPurpose) override {
|
||||
return Success;
|
||||
}
|
||||
|
||||
virtual Result NetscapeStepUpMatchesServerAuth(
|
||||
Time notBefore, /*out*/ bool& matches) override {
|
||||
matches = false;
|
||||
return Success;
|
||||
}
|
||||
|
||||
virtual void NoteAuxiliaryExtension(AuxiliaryExtension extension,
|
||||
Input extensionData) override {}
|
||||
|
||||
virtual Result DigestBuf(Input item, DigestAlgorithm digestAlg,
|
||||
/*out*/ uint8_t* digestBuf,
|
||||
size_t digestBufLen) override {
|
||||
return DigestBufNSS(item, digestAlg, digestBuf, digestBufLen);
|
||||
}
|
||||
|
||||
private:
|
||||
const uint8_t** mCertificates;
|
||||
const uint16_t* mCertificateLengths;
|
||||
size_t mNumCertificates;
|
||||
const uint8_t* mRootSHA256Digest;
|
||||
};
|
||||
|
||||
class CodeSigningNameMatchingPolicy : public NameMatchingPolicy {
|
||||
public:
|
||||
virtual Result FallBackToCommonName(
|
||||
Time notBefore,
|
||||
/*out*/ FallBackToSearchWithinSubject& fallBackToCommonName) override {
|
||||
fallBackToCommonName = FallBackToSearchWithinSubject::No;
|
||||
return Success;
|
||||
}
|
||||
};
|
||||
|
||||
bool VerifyCodeSigningCertificateChain(
|
||||
const uint8_t** certificates, const uint16_t* certificateLengths,
|
||||
size_t numCertificates, uint64_t secondsSinceEpoch,
|
||||
const uint8_t* rootSHA256Digest, const uint8_t* hostname,
|
||||
size_t hostnameLength, PRErrorCode* error) {
|
||||
if (!error) {
|
||||
return false;
|
||||
}
|
||||
if (!certificates || !certificateLengths || numCertificates < 1 ||
|
||||
!rootSHA256Digest) {
|
||||
*error = SEC_ERROR_INVALID_ARGS;
|
||||
return false;
|
||||
}
|
||||
|
||||
CodeSigningTrustDomain trustDomain(certificates, certificateLengths,
|
||||
numCertificates, rootSHA256Digest);
|
||||
Input certificate;
|
||||
Result rv = certificate.Init(certificates[0], certificateLengths[0]);
|
||||
if (rv != Success) {
|
||||
*error = MapResultToPRErrorCode(rv);
|
||||
return false;
|
||||
}
|
||||
Time time = TimeFromEpochInSeconds(secondsSinceEpoch);
|
||||
rv = BuildCertChain(
|
||||
trustDomain, certificate, time, EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::noParticularKeyUsageRequired, KeyPurposeId::id_kp_codeSigning,
|
||||
CertPolicyId::anyPolicy, nullptr);
|
||||
if (rv != Success) {
|
||||
*error = MapResultToPRErrorCode(rv);
|
||||
return false;
|
||||
}
|
||||
Input hostnameInput;
|
||||
rv = hostnameInput.Init(hostname, hostnameLength);
|
||||
if (rv != Success) {
|
||||
*error = MapResultToPRErrorCode(rv);
|
||||
return false;
|
||||
}
|
||||
CodeSigningNameMatchingPolicy nameMatchingPolicy;
|
||||
rv = CheckCertHostname(certificate, hostnameInput, nameMatchingPolicy);
|
||||
if (rv != Success) {
|
||||
*error = MapResultToPRErrorCode(rv);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This code is made available to you under your choice of the following sets
|
||||
* of licensing terms:
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This code is made available to you under your choice of the following sets
|
||||
* of licensing terms:
|
||||
*/
|
||||
|
|
@ -99,12 +100,13 @@ CheckSignatureAlgorithm(TrustDomain& trustDomain,
|
|||
|
||||
switch (publicKeyAlg) {
|
||||
case der::PublicKeyAlgorithm::RSA_PKCS1:
|
||||
case der::PublicKeyAlgorithm::RSA_PSS:
|
||||
{
|
||||
// The RSA computation may give a result that requires fewer bytes to
|
||||
// encode than the public key (since it is modular arithmetic). However,
|
||||
// the last step of generating a PKCS#1.5 signature is the I2OSP
|
||||
// procedure, which pads any such shorter result with zeros so that it
|
||||
// is exactly the same length as the public key.
|
||||
// encode than the modulus (since it is modular arithmetic). However,
|
||||
// the last step of generating a RSA-PKCS#1.5 or -PSS signature is the
|
||||
// I2OSP procedure, which pads any such shorter result with zeros so that
|
||||
// it is exactly the same length as the modulus.
|
||||
unsigned int signatureSizeInBits = signedData.signature.GetLength() * 8u;
|
||||
return trustDomain.CheckRSAPublicKeyModulusSizeInBits(
|
||||
endEntityOrCA, signatureSizeInBits);
|
||||
|
|
@ -116,11 +118,6 @@ CheckSignatureAlgorithm(TrustDomain& trustDomain,
|
|||
// for any curve that we support, the chances of us encountering a curve
|
||||
// during path building is too low to be worth bothering with.
|
||||
break;
|
||||
case der::PublicKeyAlgorithm::Uninitialized:
|
||||
{
|
||||
assert(false);
|
||||
return Result::FATAL_ERROR_LIBRARY_FAILURE;
|
||||
}
|
||||
MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This code is made available to you under your choice of the following sets
|
||||
* of licensing terms:
|
||||
*/
|
||||
|
|
@ -82,29 +83,6 @@ ReadTagAndGetValue(Reader& input, /*out*/ uint8_t& tag, /*out*/ Input& value)
|
|||
return input.Skip(length, value);
|
||||
}
|
||||
|
||||
static Result
|
||||
OptionalNull(Reader& input)
|
||||
{
|
||||
if (input.Peek(NULLTag)) {
|
||||
return Null(input);
|
||||
}
|
||||
return Success;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
Result
|
||||
AlgorithmIdentifierValue(Reader& input, /*out*/ Reader& algorithmOIDValue)
|
||||
{
|
||||
Result rv = ExpectTagAndGetValue(input, der::OIDTag, algorithmOIDValue);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
return OptionalNull(input);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Result
|
||||
SignatureAlgorithmIdentifierValue(Reader& input,
|
||||
/*out*/ PublicKeyAlgorithm& publicKeyAlgorithm,
|
||||
|
|
@ -115,13 +93,39 @@ SignatureAlgorithmIdentifierValue(Reader& input,
|
|||
//
|
||||
// RFC 4055 Section 5 and RFC 3279 Section 2.2.1 both say that parameters for
|
||||
// RSA must be encoded as NULL; we relax that requirement by allowing the
|
||||
// NULL to be omitted, to match all the other signature algorithms we support
|
||||
// and for compatibility.
|
||||
// NULL to be omitted.
|
||||
//
|
||||
// RFC 8017 Appendix A.2.3 specifies the format of the parameters for
|
||||
// RSA-PSS. The CA/Browser Forum Baseline Requirements (as of 1.8.1)
|
||||
// specify three specific parameters that may be used with RSA-PSS:
|
||||
// * SHA-256, MGF-1 with SHA-256, and a salt length of 32 bytes
|
||||
// * SHA-384, MGF-1 with SHA-384, and a salt length of 48 bytes
|
||||
// * SHA-512, MGF-1 with SHA-512, and a salt length of 64 bytes
|
||||
// as well as the corresponding specific encodings that must be used
|
||||
// for the entire AlgorithmIdentifier:
|
||||
// * 304106092a864886f70d01010a3034a00f300d0609608648016503040201
|
||||
// 0500a11c301a06092a864886f70d010108300d0609608648016503040201
|
||||
// 0500a203020120
|
||||
// * 304106092a864886f70d01010a3034a00f300d0609608648016503040202
|
||||
// 0500a11c301a06092a864886f70d010108300d0609608648016503040202
|
||||
// 0500a203020130
|
||||
// * 304106092a864886f70d01010a3034a00f300d0609608648016503040203
|
||||
// 0500a11c301a06092a864886f70d010108300d0609608648016503040203
|
||||
// 0500a203020140
|
||||
// Note that these encodings include the outer SEQUENCE and length bytes;
|
||||
// in this implementation, the caller has already validated those bytes.
|
||||
// Currently these are the only sets of parameters mozilla::pkix supports.
|
||||
Reader algorithmID;
|
||||
Result rv = AlgorithmIdentifierValue(input, algorithmID);
|
||||
Result rv = ExpectTagAndGetValue(input, der::OIDTag, algorithmID);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
Input algorithmParamsInput;
|
||||
rv = input.SkipToEnd(algorithmParamsInput);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
Reader algorithmParams(algorithmParamsInput);
|
||||
|
||||
// RFC 5758 Section 3.2 (ecdsa-with-SHA224 is intentionally excluded)
|
||||
// python DottedOIDToCode.py ecdsa-with-SHA256 1.2.840.10045.4.3.2
|
||||
|
|
@ -172,6 +176,41 @@ SignatureAlgorithmIdentifierValue(Reader& input,
|
|||
0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x01
|
||||
};
|
||||
|
||||
// RFC 8017 Appendix A.2.3
|
||||
// python DottedOIDToCode.py id-RSA-PSS 1.2.840.113549.1.1.10
|
||||
static const uint8_t id_RSA_PSS[] = {
|
||||
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0a
|
||||
};
|
||||
|
||||
// CA/B Forum BR 1.8.1 Section 7.1.3.2.1
|
||||
// Params for RSA-PSS with SHA-256, MGF-1 with SHA-256, and a salt length
|
||||
// of 32 bytes:
|
||||
static const uint8_t rsaPSSWithSHA256MGF1WithSHA256Salt32[] = {
|
||||
0x30, 0x34, 0xa0, 0x0f, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
|
||||
0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0xa1, 0x1c, 0x30, 0x1a, 0x06,
|
||||
0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x08, 0x30, 0x0d,
|
||||
0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
|
||||
0x00, 0xa2, 0x03, 0x02, 0x01, 0x20
|
||||
};
|
||||
// Params for RSA-PSS with SHA-384, MGF-1 with SHA-384, and a salt length
|
||||
// of 48 bytes:
|
||||
static const uint8_t rsaPSSWithSHA384MGF1WithSHA384Salt48[] = {
|
||||
0x30, 0x34, 0xa0, 0x0f, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
|
||||
0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0xa1, 0x1c, 0x30, 0x1a, 0x06,
|
||||
0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x08, 0x30, 0x0d,
|
||||
0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05,
|
||||
0x00, 0xa2, 0x03, 0x02, 0x01, 0x30
|
||||
};
|
||||
// Params for RSA-PSS with SHA-512, MGF-1 with SHA-512, and a salt length
|
||||
// of 64 bytes:
|
||||
static const uint8_t rsaPSSWithSHA512MGF1WithSHA512Salt64[] = {
|
||||
0x30, 0x34, 0xa0, 0x0f, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
|
||||
0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0xa1, 0x1c, 0x30, 0x1a, 0x06,
|
||||
0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x08, 0x30, 0x0d,
|
||||
0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
|
||||
0x00, 0xa2, 0x03, 0x02, 0x01, 0x40
|
||||
};
|
||||
|
||||
// Matching is attempted based on a rough estimate of the commonality of the
|
||||
// algorithm, to minimize the number of MatchRest calls.
|
||||
if (algorithmID.MatchRest(sha256WithRSAEncryption)) {
|
||||
|
|
@ -199,25 +238,62 @@ SignatureAlgorithmIdentifierValue(Reader& input,
|
|||
publicKeyAlgorithm = PublicKeyAlgorithm::RSA_PKCS1;
|
||||
digestAlgorithm = DigestAlgorithm::sha512;
|
||||
} else if (algorithmID.MatchRest(sha1WithRSASignature)) {
|
||||
// XXX(bug 1042479): recognize this old OID for compatibility.
|
||||
// This old OID is recognized for compatibility (see bug 1042479).
|
||||
publicKeyAlgorithm = PublicKeyAlgorithm::RSA_PKCS1;
|
||||
digestAlgorithm = DigestAlgorithm::sha1;
|
||||
} else if (algorithmID.MatchRest(id_RSA_PSS)) {
|
||||
publicKeyAlgorithm = PublicKeyAlgorithm::RSA_PSS;
|
||||
if (algorithmParams.MatchRest(rsaPSSWithSHA256MGF1WithSHA256Salt32)) {
|
||||
digestAlgorithm = DigestAlgorithm::sha256;
|
||||
} else if (algorithmParams.MatchRest(rsaPSSWithSHA384MGF1WithSHA384Salt48)) {
|
||||
digestAlgorithm = DigestAlgorithm::sha384;
|
||||
} else if (algorithmParams.MatchRest(rsaPSSWithSHA512MGF1WithSHA512Salt64)) {
|
||||
digestAlgorithm = DigestAlgorithm::sha512;
|
||||
} else {
|
||||
return Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED;
|
||||
}
|
||||
} else {
|
||||
return Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED;
|
||||
}
|
||||
|
||||
// Ensure that for non-RSA-PSS algorithms, the params are NULL or omitted.
|
||||
if (publicKeyAlgorithm != PublicKeyAlgorithm::RSA_PSS) {
|
||||
if (algorithmParams.Peek(NULLTag)) {
|
||||
rv = Null(algorithmParams);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
if (!algorithmParams.AtEnd()) {
|
||||
return Result::ERROR_BAD_DER;
|
||||
}
|
||||
}
|
||||
|
||||
return Success;
|
||||
}
|
||||
|
||||
Result
|
||||
DigestAlgorithmIdentifier(Reader& input, /*out*/ DigestAlgorithm& algorithm)
|
||||
{
|
||||
// AlgorithmIdentifier ::= SEQUENCE {
|
||||
// algorithm OBJECT IDENTIFIER,
|
||||
// parameters ANY DEFINED BY algorithm OPTIONAL }
|
||||
return der::Nested(input, SEQUENCE, [&algorithm](Reader& r) -> Result {
|
||||
Reader algorithmID;
|
||||
Result rv = AlgorithmIdentifierValue(r, algorithmID);
|
||||
Result rv = ExpectTagAndGetValue(r, der::OIDTag, algorithmID);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
// The parameters are expected to be NULL or omitted.
|
||||
if (r.Peek(NULLTag)) {
|
||||
rv = Null(r);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
if (!r.AtEnd()) {
|
||||
return Result::ERROR_BAD_DER;
|
||||
}
|
||||
|
||||
// RFC 4055 Section 2.1
|
||||
// python DottedOIDToCode.py id-sha1 1.3.14.3.2.26
|
||||
|
|
@ -607,4 +683,58 @@ OptionalVersion(Reader& input, /*out*/ Version& version)
|
|||
});
|
||||
}
|
||||
|
||||
// From RFC 5480 Appendix A:
|
||||
// ECDSA-Sig-Value ::= SEQUENCE {
|
||||
// r INTEGER,
|
||||
// s INTEGER
|
||||
// }
|
||||
Result
|
||||
ECDSASigValue(Input ecdsaSignature, /*out*/ Input& r, /*out*/ Input& s) {
|
||||
Reader rAndS;
|
||||
Result rv = ExpectTagAndGetValueAtEnd(ecdsaSignature, SEQUENCE, rAndS);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
Input rInput;
|
||||
Input::size_type rSignificantBytes;
|
||||
rv = PositiveInteger(rAndS, rInput, &rSignificantBytes);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
Reader rReader(rInput);
|
||||
// Address potential leading 0 byte due to DER encoding.
|
||||
if (rSignificantBytes + 1 == rInput.GetLength()) {
|
||||
rv = rReader.Skip(1);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
rv = rReader.SkipToEnd(r);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
Input sInput;
|
||||
Input::size_type sSignificantBytes;
|
||||
rv = PositiveInteger(rAndS, sInput, &sSignificantBytes);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
Reader sReader(sInput);
|
||||
// Address potential leading 0 byte due to DER encoding.
|
||||
if (sSignificantBytes + 1 == sInput.GetLength()) {
|
||||
rv = sReader.Skip(1);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
rv = sReader.SkipToEnd(s);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return End(rAndS);
|
||||
}
|
||||
|
||||
} } } // namespace mozilla::pkix::der
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
/* Copyright 2014 Mozilla Contributors
|
||||
* Copyright 2026 Moonchild Productions
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -170,6 +171,12 @@ enum class IDRole
|
|||
NameConstraint = 2,
|
||||
};
|
||||
|
||||
enum class NameConstraintsSubtrees : uint8_t
|
||||
{
|
||||
permittedSubtrees = der::CONSTRUCTED | der::CONTEXT_SPECIFIC | 0,
|
||||
excludedSubtrees = der::CONSTRUCTED | der::CONTEXT_SPECIFIC | 1
|
||||
};
|
||||
|
||||
enum class AllowWildcards { No = 0, Yes = 1 };
|
||||
|
||||
// DNSName constraints implicitly allow subdomain matching when there is no
|
||||
|
|
@ -182,16 +189,22 @@ enum class AllowDotlessSubdomainMatches { No = 0, Yes = 1 };
|
|||
bool IsValidDNSID(Input hostname, IDRole idRole,
|
||||
AllowWildcards allowWildcards);
|
||||
|
||||
// `subtreesType` is relevant only when `referenceDNSIDRole` is
|
||||
// `IDRole::NameConstraint`.
|
||||
Result MatchPresentedDNSIDWithReferenceDNSID(
|
||||
Input presentedDNSID,
|
||||
AllowWildcards allowWildcards,
|
||||
AllowDotlessSubdomainMatches allowDotlessSubdomainMatches,
|
||||
IDRole referenceDNSIDRole,
|
||||
/*optional*/ const NameConstraintsSubtrees* subtreesType,
|
||||
Input referenceDNSID,
|
||||
/*out*/ bool& matches);
|
||||
|
||||
// `subtreesType` is relevant only when `referenceDNSIDRole` is
|
||||
// `IDRole::NameConstraint`.
|
||||
Result MatchPresentedRFC822NameWithReferenceRFC822Name(
|
||||
Input presentedRFC822Name, IDRole referenceRFC822NameRole,
|
||||
/*optional*/ const NameConstraintsSubtrees* subtreesType,
|
||||
Input referenceRFC822Name, /*out*/ bool& matches);
|
||||
|
||||
} // namespace
|
||||
|
|
@ -210,7 +223,7 @@ MatchPresentedDNSIDWithReferenceDNSID(Input presentedDNSID,
|
|||
return MatchPresentedDNSIDWithReferenceDNSID(
|
||||
presentedDNSID, AllowWildcards::Yes,
|
||||
AllowDotlessSubdomainMatches::Yes, IDRole::ReferenceID,
|
||||
referenceDNSID, matches);
|
||||
nullptr, referenceDNSID, matches);
|
||||
}
|
||||
|
||||
// Verify that the given end-entity cert, which is assumed to have been already
|
||||
|
|
@ -279,6 +292,23 @@ CheckCertHostname(Input endEntityCertDER, Input hostname,
|
|||
}
|
||||
}
|
||||
|
||||
// A strict name matching policy for CheckCertHostname which never
|
||||
// falls back to searching within the subject name.
|
||||
Result StrictNameMatchingPolicy::FallBackToCommonName(
|
||||
Time notBefore,
|
||||
/*out*/ FallBackToSearchWithinSubject& fallBackToCommonName) {
|
||||
fallBackToCommonName = FallBackToSearchWithinSubject::No;
|
||||
return Success;
|
||||
}
|
||||
|
||||
Result
|
||||
CheckCertHostname(Input endEntityCertDER, Input hostname)
|
||||
{
|
||||
StrictNameMatchingPolicy policy{};
|
||||
return CheckCertHostname(endEntityCertDER, hostname, policy);
|
||||
}
|
||||
|
||||
|
||||
// 4.2.1.10. Name Constraints
|
||||
Result
|
||||
CheckNameConstraints(Input encodedNameConstraints,
|
||||
|
|
@ -694,7 +724,7 @@ MatchPresentedIDWithReferenceID(GeneralNameType presentedIDType,
|
|||
rv = MatchPresentedDNSIDWithReferenceDNSID(
|
||||
presentedID, AllowWildcards::Yes,
|
||||
AllowDotlessSubdomainMatches::Yes, IDRole::ReferenceID,
|
||||
referenceID, foundMatch);
|
||||
nullptr, referenceID, foundMatch);
|
||||
break;
|
||||
|
||||
case GeneralNameType::iPAddress:
|
||||
|
|
@ -704,7 +734,7 @@ MatchPresentedIDWithReferenceID(GeneralNameType presentedIDType,
|
|||
|
||||
case GeneralNameType::rfc822Name:
|
||||
rv = MatchPresentedRFC822NameWithReferenceRFC822Name(
|
||||
presentedID, IDRole::ReferenceID, referenceID, foundMatch);
|
||||
presentedID, IDRole::ReferenceID, nullptr, referenceID, foundMatch);
|
||||
break;
|
||||
|
||||
case GeneralNameType::directoryName:
|
||||
|
|
@ -730,12 +760,6 @@ MatchPresentedIDWithReferenceID(GeneralNameType presentedIDType,
|
|||
return Success;
|
||||
}
|
||||
|
||||
enum class NameConstraintsSubtrees : uint8_t
|
||||
{
|
||||
permittedSubtrees = der::CONSTRUCTED | der::CONTEXT_SPECIFIC | 0,
|
||||
excludedSubtrees = der::CONSTRUCTED | der::CONTEXT_SPECIFIC | 1
|
||||
};
|
||||
|
||||
Result CheckPresentedIDConformsToNameConstraintsSubtrees(
|
||||
GeneralNameType presentedIDType,
|
||||
Input presentedID,
|
||||
|
|
@ -849,7 +873,7 @@ CheckPresentedIDConformsToNameConstraintsSubtrees(
|
|||
rv = MatchPresentedDNSIDWithReferenceDNSID(
|
||||
presentedID, AllowWildcards::Yes,
|
||||
AllowDotlessSubdomainMatches::Yes, IDRole::NameConstraint,
|
||||
base, matches);
|
||||
&subtreesType, base, matches);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
|
|
@ -874,7 +898,7 @@ CheckPresentedIDConformsToNameConstraintsSubtrees(
|
|||
|
||||
case GeneralNameType::rfc822Name:
|
||||
rv = MatchPresentedRFC822NameWithReferenceRFC822Name(
|
||||
presentedID, IDRole::NameConstraint, base, matches);
|
||||
presentedID, IDRole::NameConstraint, &subtreesType, base, matches);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
|
|
@ -1057,6 +1081,7 @@ MatchPresentedDNSIDWithReferenceDNSID(
|
|||
AllowWildcards allowWildcards,
|
||||
AllowDotlessSubdomainMatches allowDotlessSubdomainMatches,
|
||||
IDRole referenceDNSIDRole,
|
||||
/*optional*/ const NameConstraintsSubtrees* subtreesType,
|
||||
Input referenceDNSID,
|
||||
/*out*/ bool& matches)
|
||||
{
|
||||
|
|
@ -1147,18 +1172,28 @@ MatchPresentedDNSIDWithReferenceDNSID(
|
|||
return NotReached("Skipping '*' failed",
|
||||
Result::FATAL_ERROR_LIBRARY_FAILURE);
|
||||
}
|
||||
do {
|
||||
// This will happen if reference is a single, relative label
|
||||
if (reference.AtEnd()) {
|
||||
matches = false;
|
||||
return Success;
|
||||
}
|
||||
uint8_t referenceByte;
|
||||
if (reference.Read(referenceByte) != Success) {
|
||||
return NotReached("invalid reference ID",
|
||||
Result::FATAL_ERROR_INVALID_ARGS);
|
||||
}
|
||||
} while (!reference.Peek('.'));
|
||||
// For the permittedSubtrees of a name constraint, wildcard presented
|
||||
// DNSIDs of the form `*.example.com` only match if the name constraint is
|
||||
// of the form `.example.com` or `example.com`. To put it another way, a
|
||||
// permittedSubtrees of `foo.example.com` does not match a wildcard
|
||||
// presented DNSID of `*.example.com`, because in that case, the
|
||||
// certificate could be valid for `bar.example.com`, which does not match
|
||||
// the name constraint.
|
||||
if (referenceDNSIDRole != IDRole::NameConstraint ||
|
||||
(subtreesType && *subtreesType != NameConstraintsSubtrees::permittedSubtrees)) {
|
||||
do {
|
||||
// This will happen if reference is a single, relative label
|
||||
if (reference.AtEnd()) {
|
||||
matches = false;
|
||||
return Success;
|
||||
}
|
||||
uint8_t referenceByte;
|
||||
if (reference.Read(referenceByte) != Success) {
|
||||
return NotReached("invalid reference ID",
|
||||
Result::FATAL_ERROR_INVALID_ARGS);
|
||||
}
|
||||
} while (!reference.Peek('.'));
|
||||
}
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
|
|
@ -1515,9 +1550,12 @@ IsValidRFC822Name(Input input)
|
|||
}
|
||||
}
|
||||
|
||||
// `subtreesType` is relevant only when `referenceRFC822NameRole` is
|
||||
// `IDRole::NameConstraint`.
|
||||
Result
|
||||
MatchPresentedRFC822NameWithReferenceRFC822Name(Input presentedRFC822Name,
|
||||
IDRole referenceRFC822NameRole,
|
||||
/*optional*/ const NameConstraintsSubtrees* subtreesType,
|
||||
Input referenceRFC822Name,
|
||||
/*out*/ bool& matches)
|
||||
{
|
||||
|
|
@ -1562,6 +1600,7 @@ MatchPresentedRFC822NameWithReferenceRFC822Name(Input presentedRFC822Name,
|
|||
return MatchPresentedDNSIDWithReferenceDNSID(
|
||||
presentedDNSID, AllowWildcards::No,
|
||||
AllowDotlessSubdomainMatches::No, IDRole::NameConstraint,
|
||||
subtreesType,
|
||||
referenceRFC822Name, matches);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/*- *- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This code is made available to you under your choice of the following sets
|
||||
* of licensing terms:
|
||||
*/
|
||||
|
|
@ -39,63 +40,233 @@ namespace mozilla { namespace pkix {
|
|||
namespace {
|
||||
|
||||
Result
|
||||
VerifySignedDigest(const SignedDigest& sd,
|
||||
Input subjectPublicKeyInfo,
|
||||
SECOidTag pubKeyAlg,
|
||||
void* pkcs11PinArg)
|
||||
SubjectPublicKeyInfoToSECKEYPublicKey(Input subjectPublicKeyInfo,
|
||||
ScopedSECKEYPublicKey& publicKey)
|
||||
{
|
||||
SECOidTag digestAlg;
|
||||
switch (sd.digestAlgorithm) {
|
||||
case DigestAlgorithm::sha512: digestAlg = SEC_OID_SHA512; break;
|
||||
case DigestAlgorithm::sha384: digestAlg = SEC_OID_SHA384; break;
|
||||
case DigestAlgorithm::sha256: digestAlg = SEC_OID_SHA256; break;
|
||||
case DigestAlgorithm::sha1: digestAlg = SEC_OID_SHA1; break;
|
||||
MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM
|
||||
}
|
||||
|
||||
SECItem subjectPublicKeyInfoSECItem =
|
||||
UnsafeMapInputToSECItem(subjectPublicKeyInfo);
|
||||
ScopedCERTSubjectPublicKeyInfo
|
||||
spki(SECKEY_DecodeDERSubjectPublicKeyInfo(&subjectPublicKeyInfoSECItem));
|
||||
SECItem subjectPublicKeyInfoSECItem(
|
||||
UnsafeMapInputToSECItem(subjectPublicKeyInfo));
|
||||
ScopedCERTSubjectPublicKeyInfo spki(
|
||||
SECKEY_DecodeDERSubjectPublicKeyInfo(&subjectPublicKeyInfoSECItem));
|
||||
if (!spki) {
|
||||
return MapPRErrorCodeToResult(PR_GetError());
|
||||
}
|
||||
ScopedSECKEYPublicKey
|
||||
pubKey(SECKEY_ExtractPublicKey(spki.get()));
|
||||
if (!pubKey) {
|
||||
publicKey.reset(SECKEY_ExtractPublicKey(spki.get()));
|
||||
if (!publicKey) {
|
||||
return MapPRErrorCodeToResult(PR_GetError());
|
||||
}
|
||||
|
||||
SECItem digestSECItem(UnsafeMapInputToSECItem(sd.digest));
|
||||
SECItem signatureSECItem(UnsafeMapInputToSECItem(sd.signature));
|
||||
SECStatus srv = VFY_VerifyDigestDirect(&digestSECItem, pubKey.get(),
|
||||
&signatureSECItem, pubKeyAlg,
|
||||
digestAlg, pkcs11PinArg);
|
||||
if (srv != SECSuccess) {
|
||||
return MapPRErrorCodeToResult(PR_GetError());
|
||||
}
|
||||
|
||||
return Success;
|
||||
}
|
||||
|
||||
template<size_t N>
|
||||
Result
|
||||
VerifySignedData(SECKEYPublicKey* publicKey, CK_MECHANISM_TYPE mechanism,
|
||||
SECItem* params, SECItem* signature, SECItem* data,
|
||||
SECOidTag (&policyTags)[N], void* pkcs11PinArg)
|
||||
{
|
||||
// Hash and signature algorithms can be disabled by policy in NSS. However,
|
||||
// the policy engine in NSS is not currently sophisticated enough to, for
|
||||
// example, infer that disabling SEC_OID_SHA1 (i.e. the hash algorithm SHA1)
|
||||
// should also disable SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION. Thus, this
|
||||
// implementation checks the signature algorithm, the hash algorithm, and the
|
||||
// signature algorithm with the hash algorithm together.
|
||||
for (size_t i = 0; i < sizeof(policyTags) / sizeof(policyTags[0]); i++) {
|
||||
SECOidTag policyTag = policyTags[i];
|
||||
uint32_t policyFlags;
|
||||
if (NSS_GetAlgorithmPolicy(policyTag, &policyFlags) != SECSuccess) {
|
||||
return MapPRErrorCodeToResult(PR_GetError());
|
||||
}
|
||||
if (!(policyFlags & NSS_USE_ALG_IN_ANY_SIGNATURE)) {
|
||||
return Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED;
|
||||
}
|
||||
}
|
||||
SECStatus srv = PK11_VerifyWithMechanism(publicKey, mechanism, params,
|
||||
signature, data, pkcs11PinArg);
|
||||
if (srv != SECSuccess) {
|
||||
return MapPRErrorCodeToResult(PR_GetError());
|
||||
}
|
||||
return Success;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
Result
|
||||
VerifyRSAPKCS1SignedDigestNSS(const SignedDigest& sd,
|
||||
Input subjectPublicKeyInfo,
|
||||
void* pkcs11PinArg)
|
||||
VerifyRSAPKCS1SignedDataNSS(Input data, DigestAlgorithm digestAlgorithm,
|
||||
Input signature, Input subjectPublicKeyInfo, void* pkcs11PinArg)
|
||||
{
|
||||
return VerifySignedDigest(sd, subjectPublicKeyInfo,
|
||||
SEC_OID_PKCS1_RSA_ENCRYPTION, pkcs11PinArg);
|
||||
ScopedSECKEYPublicKey publicKey;
|
||||
Result rv = SubjectPublicKeyInfoToSECKEYPublicKey(subjectPublicKeyInfo,
|
||||
publicKey);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
SECItem signatureItem(UnsafeMapInputToSECItem(signature));
|
||||
SECItem dataItem(UnsafeMapInputToSECItem(data));
|
||||
CK_MECHANISM_TYPE mechanism;
|
||||
SECOidTag signaturePolicyTag = SEC_OID_PKCS1_RSA_ENCRYPTION;
|
||||
SECOidTag hashPolicyTag;
|
||||
SECOidTag combinedPolicyTag;
|
||||
switch (digestAlgorithm) {
|
||||
case DigestAlgorithm::sha512:
|
||||
mechanism = CKM_SHA512_RSA_PKCS;
|
||||
hashPolicyTag = SEC_OID_SHA512;
|
||||
combinedPolicyTag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION;
|
||||
break;
|
||||
case DigestAlgorithm::sha384:
|
||||
mechanism = CKM_SHA384_RSA_PKCS;
|
||||
hashPolicyTag = SEC_OID_SHA384;
|
||||
combinedPolicyTag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION;
|
||||
break;
|
||||
case DigestAlgorithm::sha256:
|
||||
mechanism = CKM_SHA256_RSA_PKCS;
|
||||
hashPolicyTag = SEC_OID_SHA256;
|
||||
combinedPolicyTag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION;
|
||||
break;
|
||||
case DigestAlgorithm::sha1:
|
||||
mechanism = CKM_SHA1_RSA_PKCS;
|
||||
hashPolicyTag = SEC_OID_SHA1;
|
||||
combinedPolicyTag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
|
||||
break;
|
||||
MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM
|
||||
}
|
||||
SECOidTag policyTags[3] =
|
||||
{ signaturePolicyTag, hashPolicyTag, combinedPolicyTag };
|
||||
return VerifySignedData(publicKey.get(), mechanism, nullptr, &signatureItem,
|
||||
&dataItem, policyTags, pkcs11PinArg);
|
||||
}
|
||||
|
||||
Result
|
||||
VerifyECDSASignedDigestNSS(const SignedDigest& sd,
|
||||
Input subjectPublicKeyInfo,
|
||||
void* pkcs11PinArg)
|
||||
VerifyRSAPSSSignedDataNSS(Input data, DigestAlgorithm digestAlgorithm,
|
||||
Input signature, Input subjectPublicKeyInfo, void* pkcs11PinArg)
|
||||
{
|
||||
return VerifySignedDigest(sd, subjectPublicKeyInfo,
|
||||
SEC_OID_ANSIX962_EC_PUBLIC_KEY, pkcs11PinArg);
|
||||
ScopedSECKEYPublicKey publicKey;
|
||||
Result rv = SubjectPublicKeyInfoToSECKEYPublicKey(subjectPublicKeyInfo,
|
||||
publicKey);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
SECItem signatureItem(UnsafeMapInputToSECItem(signature));
|
||||
SECItem dataItem(UnsafeMapInputToSECItem(data));
|
||||
CK_MECHANISM_TYPE mechanism;
|
||||
SECOidTag signaturePolicyTag = SEC_OID_PKCS1_RSA_PSS_SIGNATURE;
|
||||
SECOidTag hashPolicyTag;
|
||||
CK_RSA_PKCS_PSS_PARAMS rsaPSSParams;
|
||||
switch (digestAlgorithm) {
|
||||
case DigestAlgorithm::sha512:
|
||||
mechanism = CKM_SHA512_RSA_PKCS_PSS;
|
||||
hashPolicyTag = SEC_OID_SHA512;
|
||||
rsaPSSParams.hashAlg = CKM_SHA512;
|
||||
rsaPSSParams.mgf = CKG_MGF1_SHA512;
|
||||
rsaPSSParams.sLen = 64;
|
||||
break;
|
||||
case DigestAlgorithm::sha384:
|
||||
mechanism = CKM_SHA384_RSA_PKCS_PSS;
|
||||
hashPolicyTag = SEC_OID_SHA384;
|
||||
rsaPSSParams.hashAlg = CKM_SHA384;
|
||||
rsaPSSParams.mgf = CKG_MGF1_SHA384;
|
||||
rsaPSSParams.sLen = 48;
|
||||
break;
|
||||
case DigestAlgorithm::sha256:
|
||||
mechanism = CKM_SHA256_RSA_PKCS_PSS;
|
||||
hashPolicyTag = SEC_OID_SHA256;
|
||||
rsaPSSParams.hashAlg = CKM_SHA256;
|
||||
rsaPSSParams.mgf = CKG_MGF1_SHA256;
|
||||
rsaPSSParams.sLen = 32;
|
||||
break;
|
||||
case DigestAlgorithm::sha1:
|
||||
return Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED;
|
||||
break;
|
||||
MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM
|
||||
}
|
||||
SECItem params;
|
||||
params.data = reinterpret_cast<unsigned char*>(&rsaPSSParams);
|
||||
params.len = sizeof(CK_RSA_PKCS_PSS_PARAMS);
|
||||
SECOidTag policyTags[2] = { signaturePolicyTag, hashPolicyTag };
|
||||
return VerifySignedData(publicKey.get(), mechanism, ¶ms, &signatureItem,
|
||||
&dataItem, policyTags, pkcs11PinArg);
|
||||
}
|
||||
|
||||
Result
|
||||
EncodedECDSASignatureToRawPoint(Input signature,
|
||||
const ScopedSECKEYPublicKey& publicKey, ScopedSECItem& result) {
|
||||
Input r;
|
||||
Input s;
|
||||
Result rv = der::ECDSASigValue(signature, r, s);
|
||||
if (rv != Success) {
|
||||
return Result::ERROR_BAD_SIGNATURE;
|
||||
}
|
||||
size_t signatureLength = SECKEY_SignatureLen(publicKey.get());
|
||||
if (signatureLength == 0) {
|
||||
return MapPRErrorCodeToResult(PR_GetError());
|
||||
}
|
||||
if (signatureLength % 2 != 0) {
|
||||
return Result::FATAL_ERROR_LIBRARY_FAILURE;
|
||||
}
|
||||
size_t coordinateLength = signatureLength / 2;
|
||||
if (r.GetLength() > coordinateLength || s.GetLength() > coordinateLength) {
|
||||
return Result::ERROR_BAD_SIGNATURE;
|
||||
}
|
||||
ScopedSECItem signatureItem(
|
||||
SECITEM_AllocItem(nullptr, nullptr, signatureLength));
|
||||
if (!signatureItem) {
|
||||
return Result::FATAL_ERROR_NO_MEMORY;
|
||||
}
|
||||
memset(signatureItem->data, 0, signatureLength);
|
||||
memcpy(signatureItem->data + (coordinateLength - r.GetLength()),
|
||||
r.UnsafeGetData(), r.GetLength());
|
||||
memcpy(signatureItem->data + (2 * coordinateLength - s.GetLength()),
|
||||
s.UnsafeGetData(), s.GetLength());
|
||||
result.swap(signatureItem);
|
||||
return Success;
|
||||
}
|
||||
|
||||
Result
|
||||
VerifyECDSASignedDataNSS(Input data, DigestAlgorithm digestAlgorithm,
|
||||
Input signature, Input subjectPublicKeyInfo, void* pkcs11PinArg)
|
||||
{
|
||||
ScopedSECKEYPublicKey publicKey;
|
||||
Result rv = SubjectPublicKeyInfoToSECKEYPublicKey(subjectPublicKeyInfo,
|
||||
publicKey);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
ScopedSECItem signatureItem;
|
||||
rv = EncodedECDSASignatureToRawPoint(signature, publicKey, signatureItem);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
SECItem dataItem(UnsafeMapInputToSECItem(data));
|
||||
CK_MECHANISM_TYPE mechanism;
|
||||
SECOidTag signaturePolicyTag = SEC_OID_ANSIX962_EC_PUBLIC_KEY;
|
||||
SECOidTag hashPolicyTag;
|
||||
SECOidTag combinedPolicyTag;
|
||||
switch (digestAlgorithm) {
|
||||
case DigestAlgorithm::sha512:
|
||||
mechanism = CKM_ECDSA_SHA512;
|
||||
hashPolicyTag = SEC_OID_SHA512;
|
||||
combinedPolicyTag = SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE;
|
||||
break;
|
||||
case DigestAlgorithm::sha384:
|
||||
mechanism = CKM_ECDSA_SHA384;
|
||||
hashPolicyTag = SEC_OID_SHA384;
|
||||
combinedPolicyTag = SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE;
|
||||
break;
|
||||
case DigestAlgorithm::sha256:
|
||||
mechanism = CKM_ECDSA_SHA256;
|
||||
hashPolicyTag = SEC_OID_SHA256;
|
||||
combinedPolicyTag = SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE;
|
||||
break;
|
||||
case DigestAlgorithm::sha1:
|
||||
mechanism = CKM_ECDSA_SHA1;
|
||||
hashPolicyTag = SEC_OID_SHA1;
|
||||
combinedPolicyTag = SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE;
|
||||
break;
|
||||
MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM
|
||||
}
|
||||
SECOidTag policyTags[3] =
|
||||
{ signaturePolicyTag, hashPolicyTag, combinedPolicyTag };
|
||||
return VerifySignedData(publicKey.get(), mechanism, nullptr,
|
||||
signatureItem.get(), &dataItem, policyTags, pkcs11PinArg);
|
||||
}
|
||||
|
||||
Result
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This code is made available to you under your choice of the following sets
|
||||
* of licensing terms:
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/*- *- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This code is made available to you under your choice of the following sets
|
||||
* of licensing terms:
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This code is made available to you under your choice of the following sets
|
||||
* of licensing terms:
|
||||
*/
|
||||
|
|
@ -74,4 +75,18 @@ TimeFromEpochInSeconds(uint64_t secondsSinceEpoch)
|
|||
return TimeFromElapsedSecondsAD(seconds);
|
||||
}
|
||||
|
||||
Result
|
||||
SecondsSinceEpochFromTime(Time time, uint64_t* outSeconds)
|
||||
{
|
||||
if (!outSeconds) {
|
||||
return Result::FATAL_ERROR_INVALID_ARGS;
|
||||
}
|
||||
Time epoch = TimeFromEpochInSeconds(0);
|
||||
if (time < epoch) {
|
||||
return Result::FATAL_ERROR_INVALID_ARGS;
|
||||
}
|
||||
*outSeconds = Duration(time, epoch).durationInSeconds;
|
||||
return Result::Success;
|
||||
}
|
||||
|
||||
} } // namespace mozilla::pkix
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This code is made available to you under your choice of the following sets
|
||||
* of licensing terms:
|
||||
*/
|
||||
|
|
@ -26,15 +27,15 @@
|
|||
namespace mozilla { namespace pkix {
|
||||
|
||||
Result
|
||||
DigestSignedData(TrustDomain& trustDomain,
|
||||
VerifySignedData(TrustDomain& trustDomain,
|
||||
const der::SignedDataWithSignature& signedData,
|
||||
/*out*/ uint8_t(&digestBuf)[MAX_DIGEST_SIZE_IN_BYTES],
|
||||
/*out*/ der::PublicKeyAlgorithm& publicKeyAlg,
|
||||
/*out*/ SignedDigest& signedDigest)
|
||||
Input signerSubjectPublicKeyInfo)
|
||||
{
|
||||
der::PublicKeyAlgorithm publicKeyAlg;
|
||||
DigestAlgorithm digestAlgorithm;
|
||||
Reader signatureAlg(signedData.algorithm);
|
||||
Result rv = der::SignatureAlgorithmIdentifierValue(
|
||||
signatureAlg, publicKeyAlg, signedDigest.digestAlgorithm);
|
||||
signatureAlg, publicKeyAlg, digestAlgorithm);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
|
|
@ -42,57 +43,18 @@ DigestSignedData(TrustDomain& trustDomain,
|
|||
return Result::ERROR_BAD_DER;
|
||||
}
|
||||
|
||||
size_t digestLen = DigestAlgorithmToSizeInBytes(signedDigest.digestAlgorithm);
|
||||
assert(digestLen <= sizeof(digestBuf));
|
||||
|
||||
rv = trustDomain.DigestBuf(signedData.data, signedDigest.digestAlgorithm,
|
||||
digestBuf, digestLen);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
rv = signedDigest.digest.Init(digestBuf, digestLen);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return signedDigest.signature.Init(signedData.signature);
|
||||
}
|
||||
|
||||
Result
|
||||
VerifySignedDigest(TrustDomain& trustDomain,
|
||||
der::PublicKeyAlgorithm publicKeyAlg,
|
||||
const SignedDigest& signedDigest,
|
||||
Input signerSubjectPublicKeyInfo)
|
||||
{
|
||||
switch (publicKeyAlg) {
|
||||
case der::PublicKeyAlgorithm::ECDSA:
|
||||
return trustDomain.VerifyECDSASignedDigest(signedDigest,
|
||||
signerSubjectPublicKeyInfo);
|
||||
return trustDomain.VerifyECDSASignedData(signedData.data,
|
||||
digestAlgorithm, signedData.signature, signerSubjectPublicKeyInfo);
|
||||
case der::PublicKeyAlgorithm::RSA_PKCS1:
|
||||
return trustDomain.VerifyRSAPKCS1SignedDigest(signedDigest,
|
||||
signerSubjectPublicKeyInfo);
|
||||
case der::PublicKeyAlgorithm::Uninitialized:
|
||||
assert(false);
|
||||
return Result::FATAL_ERROR_LIBRARY_FAILURE;
|
||||
return trustDomain.VerifyRSAPKCS1SignedData(signedData.data,
|
||||
digestAlgorithm, signedData.signature, signerSubjectPublicKeyInfo);
|
||||
case der::PublicKeyAlgorithm::RSA_PSS:
|
||||
return trustDomain.VerifyRSAPSSSignedData(signedData.data,
|
||||
digestAlgorithm, signedData.signature, signerSubjectPublicKeyInfo);
|
||||
MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM
|
||||
}
|
||||
}
|
||||
|
||||
Result
|
||||
VerifySignedData(TrustDomain& trustDomain,
|
||||
const der::SignedDataWithSignature& signedData,
|
||||
Input signerSubjectPublicKeyInfo)
|
||||
{
|
||||
uint8_t digestBuf[MAX_DIGEST_SIZE_IN_BYTES];
|
||||
der::PublicKeyAlgorithm publicKeyAlg;
|
||||
SignedDigest signedDigest;
|
||||
Result rv = DigestSignedData(trustDomain, signedData, digestBuf,
|
||||
publicKeyAlg, signedDigest);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
return VerifySignedDigest(trustDomain, publicKeyAlg, signedDigest,
|
||||
signerSubjectPublicKeyInfo);
|
||||
}
|
||||
|
||||
} } // namespace mozilla::pkix
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
'standalone_static_library': 1,
|
||||
'sources': [
|
||||
'lib/pkixbuild.cpp',
|
||||
'lib/pkixc.cpp',
|
||||
'lib/pkixcert.cpp',
|
||||
'lib/pkixcheck.cpp',
|
||||
'lib/pkixder.cpp',
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This code is made available to you under your choice of the following sets
|
||||
* of licensing terms:
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This code is made available to you under your choice of the following sets
|
||||
* of licensing terms:
|
||||
*/
|
||||
|
|
@ -334,21 +335,30 @@ GenerateDSSKeyPair()
|
|||
}
|
||||
|
||||
Result
|
||||
TestVerifyECDSASignedDigest(const SignedDigest& signedDigest,
|
||||
Input subjectPublicKeyInfo)
|
||||
TestVerifyECDSASignedData(Input data, DigestAlgorithm digestAlgorithm,
|
||||
Input signature, Input subjectPublicKeyInfo)
|
||||
{
|
||||
InitNSSIfNeeded();
|
||||
return VerifyECDSASignedDigestNSS(signedDigest, subjectPublicKeyInfo,
|
||||
nullptr);
|
||||
return VerifyECDSASignedDataNSS(data, digestAlgorithm, signature,
|
||||
subjectPublicKeyInfo, nullptr);
|
||||
}
|
||||
|
||||
Result
|
||||
TestVerifyRSAPKCS1SignedDigest(const SignedDigest& signedDigest,
|
||||
Input subjectPublicKeyInfo)
|
||||
TestVerifyRSAPKCS1SignedData(Input data, DigestAlgorithm digestAlgorithm,
|
||||
Input signature, Input subjectPublicKeyInfo)
|
||||
{
|
||||
InitNSSIfNeeded();
|
||||
return VerifyRSAPKCS1SignedDigestNSS(signedDigest, subjectPublicKeyInfo,
|
||||
nullptr);
|
||||
return VerifyRSAPKCS1SignedDataNSS(data, digestAlgorithm, signature,
|
||||
subjectPublicKeyInfo, nullptr);
|
||||
}
|
||||
|
||||
Result
|
||||
TestVerifyRSAPSSSignedData(Input data, DigestAlgorithm digestAlgorithm,
|
||||
Input signature, Input subjectPublicKeyInfo)
|
||||
{
|
||||
InitNSSIfNeeded();
|
||||
return VerifyRSAPSSSignedDataNSS(data, digestAlgorithm, signature,
|
||||
subjectPublicKeyInfo, nullptr);
|
||||
}
|
||||
|
||||
Result
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This code is made available to you under your choice of the following sets
|
||||
* of licensing terms:
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -43,11 +43,11 @@ def base128(value):
|
|||
|
||||
# least significant byte has highest bit unset
|
||||
result = [value % 0x80]
|
||||
value /= 0x80
|
||||
value = value // 0x80
|
||||
|
||||
while value != 0:
|
||||
result = [0x80 | (value % 0x80)] + result
|
||||
value /= 0x80
|
||||
value = value // 0x80
|
||||
|
||||
return result
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue