mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-20 23:37:33 +09:00
Issue #1746 - Update pkix code with later NSS code.
This commit is contained in:
parent
849d42280b
commit
ed26fe34af
38 changed files with 942 additions and 1432 deletions
30
security/pkix/include/pkix-test/pkixtestnss.h
Normal file
30
security/pkix/include/pkix-test/pkixtestnss.h
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/.
|
||||
*/
|
||||
|
||||
// This file provides some implementation-specific test utilities. This is only
|
||||
// necessary because some PSM xpcshell test utilities overlap in functionality
|
||||
// with these test utilities, so the underlying implementation is shared.
|
||||
|
||||
#ifndef mozilla_pkix_test_pkixtestnss_h
|
||||
#define mozilla_pkix_test_pkixtestnss_h
|
||||
|
||||
#include <keyhi.h>
|
||||
#include <keythi.h>
|
||||
#include "nss_scoped_ptrs.h"
|
||||
#include "pkix/test/pkixtestutil.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace pkix {
|
||||
namespace test {
|
||||
|
||||
TestKeyPair* CreateTestKeyPair(const TestPublicKeyAlgorithm publicKeyAlg,
|
||||
const ScopedSECKEYPublicKey& publicKey,
|
||||
const ScopedSECKEYPrivateKey& privateKey);
|
||||
}
|
||||
}
|
||||
} // namespace mozilla::pkix::test
|
||||
|
||||
#endif // mozilla_pkix_test_pkixtestnss_h
|
||||
388
security/pkix/include/pkix-test/pkixtestutil.h
Normal file
388
security/pkix/include/pkix-test/pkixtestutil.h
Normal file
|
|
@ -0,0 +1,388 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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_test_pkixtestutil_h
|
||||
#define mozilla_pkix_test_pkixtestutil_h
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <string>
|
||||
|
||||
#include "pkix/pkixtypes.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace pkix {
|
||||
namespace test {
|
||||
|
||||
typedef std::basic_string<uint8_t> ByteString;
|
||||
|
||||
inline bool ENCODING_FAILED(const ByteString& bs) { return bs.empty(); }
|
||||
|
||||
template <size_t L>
|
||||
inline ByteString BytesToByteString(const uint8_t (&bytes)[L]) {
|
||||
return ByteString(bytes, L);
|
||||
}
|
||||
|
||||
// XXX: Ideally, we should define this instead:
|
||||
//
|
||||
// template <typename T, std::size_t N>
|
||||
// constexpr inline std::size_t
|
||||
// ArrayLength(T (&)[N])
|
||||
// {
|
||||
// return N;
|
||||
// }
|
||||
//
|
||||
// However, we don't because not all supported compilers support constexpr,
|
||||
// and we need to calculate array lengths in static_assert sometimes.
|
||||
//
|
||||
// XXX: Evaluates its argument twice
|
||||
#define MOZILLA_PKIX_ARRAY_LENGTH(x) (sizeof(x) / sizeof((x)[0]))
|
||||
|
||||
bool InputEqualsByteString(Input input, const ByteString& bs);
|
||||
ByteString InputToByteString(Input input);
|
||||
|
||||
// python DottedOIDToCode.py --tlv id-kp-OCSPSigning 1.3.6.1.5.5.7.3.9
|
||||
static const uint8_t tlv_id_kp_OCSPSigning[] = {0x06, 0x08, 0x2b, 0x06, 0x01,
|
||||
0x05, 0x05, 0x07, 0x03, 0x09};
|
||||
|
||||
// python DottedOIDToCode.py --tlv id-kp-serverAuth 1.3.6.1.5.5.7.3.1
|
||||
static const uint8_t tlv_id_kp_serverAuth[] = {0x06, 0x08, 0x2b, 0x06, 0x01,
|
||||
0x05, 0x05, 0x07, 0x03, 0x01};
|
||||
|
||||
enum class TestDigestAlgorithmID {
|
||||
MD2,
|
||||
MD5,
|
||||
SHA1,
|
||||
SHA224,
|
||||
SHA256,
|
||||
SHA384,
|
||||
SHA512,
|
||||
};
|
||||
|
||||
struct TestPublicKeyAlgorithm {
|
||||
explicit TestPublicKeyAlgorithm(const ByteString& aAlgorithmIdentifier)
|
||||
: algorithmIdentifier(aAlgorithmIdentifier) {}
|
||||
bool operator==(const TestPublicKeyAlgorithm& other) const {
|
||||
return algorithmIdentifier == other.algorithmIdentifier;
|
||||
}
|
||||
ByteString algorithmIdentifier;
|
||||
};
|
||||
|
||||
ByteString DSS_P();
|
||||
ByteString DSS_Q();
|
||||
ByteString DSS_G();
|
||||
|
||||
TestPublicKeyAlgorithm DSS();
|
||||
TestPublicKeyAlgorithm RSA_PKCS1();
|
||||
|
||||
struct TestSignatureAlgorithm {
|
||||
TestSignatureAlgorithm(const TestPublicKeyAlgorithm& publicKeyAlg,
|
||||
TestDigestAlgorithmID digestAlg,
|
||||
const ByteString& algorithmIdentifier, bool accepted);
|
||||
|
||||
TestPublicKeyAlgorithm publicKeyAlg;
|
||||
TestDigestAlgorithmID digestAlg;
|
||||
ByteString algorithmIdentifier;
|
||||
bool accepted;
|
||||
};
|
||||
|
||||
TestSignatureAlgorithm md2WithRSAEncryption();
|
||||
TestSignatureAlgorithm md5WithRSAEncryption();
|
||||
TestSignatureAlgorithm sha1WithRSAEncryption();
|
||||
TestSignatureAlgorithm sha256WithRSAEncryption();
|
||||
|
||||
// e.g. YMDHMS(2016, 12, 31, 1, 23, 45) => 2016-12-31:01:23:45 (GMT)
|
||||
mozilla::pkix::Time YMDHMS(uint16_t year, uint16_t month, uint16_t day,
|
||||
uint16_t hour, uint16_t minutes, uint16_t seconds);
|
||||
|
||||
ByteString TLV(uint8_t tag, size_t length, const ByteString& value);
|
||||
|
||||
inline ByteString TLV(uint8_t tag, const ByteString& value) {
|
||||
return TLV(tag, value.length(), value);
|
||||
}
|
||||
|
||||
// Although we can't enforce it without relying on Cuser-defined literals,
|
||||
// which aren't supported by all of our compilers yet, you should only pass
|
||||
// string literals as the last parameter to the following two functions.
|
||||
|
||||
template <size_t N>
|
||||
inline ByteString TLV(uint8_t tag, const char (&value)[N]) {
|
||||
static_assert(N > 0, "cannot have string literal of size 0");
|
||||
assert(value[N - 1] == 0);
|
||||
return TLV(tag, ByteString(reinterpret_cast<const uint8_t*>(&value), N - 1));
|
||||
}
|
||||
|
||||
template <size_t N>
|
||||
inline ByteString TLV(uint8_t tag, size_t length, const char (&value)[N]) {
|
||||
static_assert(N > 0, "cannot have string literal of size 0");
|
||||
assert(value[N - 1] == 0);
|
||||
return TLV(tag, length,
|
||||
ByteString(reinterpret_cast<const uint8_t*>(&value), N - 1));
|
||||
}
|
||||
|
||||
ByteString Boolean(bool value);
|
||||
ByteString Integer(long value);
|
||||
|
||||
ByteString CN(const ByteString&, uint8_t encodingTag = 0x0c /*UTF8String*/);
|
||||
|
||||
inline ByteString CN(const char* value,
|
||||
uint8_t encodingTag = 0x0c /*UTF8String*/) {
|
||||
return CN(
|
||||
ByteString(reinterpret_cast<const uint8_t*>(value), std::strlen(value)),
|
||||
encodingTag);
|
||||
}
|
||||
|
||||
ByteString OU(const ByteString&, uint8_t encodingTag = 0x0c /*UTF8String*/);
|
||||
|
||||
inline ByteString OU(const char* value,
|
||||
uint8_t encodingTag = 0x0c /*UTF8String*/) {
|
||||
return OU(
|
||||
ByteString(reinterpret_cast<const uint8_t*>(value), std::strlen(value)),
|
||||
encodingTag);
|
||||
}
|
||||
|
||||
ByteString emailAddress(const ByteString&);
|
||||
|
||||
inline ByteString emailAddress(const char* value) {
|
||||
return emailAddress(
|
||||
ByteString(reinterpret_cast<const uint8_t*>(value), std::strlen(value)));
|
||||
}
|
||||
|
||||
// RelativeDistinguishedName ::=
|
||||
// SET SIZE (1..MAX) OF AttributeTypeAndValue
|
||||
//
|
||||
ByteString RDN(const ByteString& avas);
|
||||
|
||||
// Name ::= CHOICE { -- only one possibility for now --
|
||||
// rdnSequence RDNSequence }
|
||||
//
|
||||
// RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
|
||||
//
|
||||
ByteString Name(const ByteString& rdns);
|
||||
|
||||
inline ByteString CNToDERName(const ByteString& cn) {
|
||||
return Name(RDN(CN(cn)));
|
||||
}
|
||||
|
||||
inline ByteString CNToDERName(const char* cn) { return Name(RDN(CN(cn))); }
|
||||
|
||||
// GeneralName ::= CHOICE {
|
||||
// otherName [0] OtherName,
|
||||
// rfc822Name [1] IA5String,
|
||||
// dNSName [2] IA5String,
|
||||
// x400Address [3] ORAddress,
|
||||
// directoryName [4] Name,
|
||||
// ediPartyName [5] EDIPartyName,
|
||||
// uniformResourceIdentifier [6] IA5String,
|
||||
// iPAddress [7] OCTET STRING,
|
||||
// registeredID [8] OBJECT IDENTIFIER }
|
||||
|
||||
inline ByteString RFC822Name(const ByteString& name) {
|
||||
// (2 << 6) means "context-specific", 1 is the GeneralName tag.
|
||||
return TLV((2 << 6) | 1, name);
|
||||
}
|
||||
|
||||
template <size_t L>
|
||||
inline ByteString RFC822Name(const char (&bytes)[L]) {
|
||||
return RFC822Name(
|
||||
ByteString(reinterpret_cast<const uint8_t*>(&bytes), L - 1));
|
||||
}
|
||||
|
||||
inline ByteString DNSName(const ByteString& name) {
|
||||
// (2 << 6) means "context-specific", 2 is the GeneralName tag.
|
||||
return TLV((2 << 6) | 2, name);
|
||||
}
|
||||
|
||||
template <size_t L>
|
||||
inline ByteString DNSName(const char (&bytes)[L]) {
|
||||
return DNSName(ByteString(reinterpret_cast<const uint8_t*>(&bytes), L - 1));
|
||||
}
|
||||
|
||||
inline ByteString DirectoryName(const ByteString& name) {
|
||||
// (2 << 6) means "context-specific", (1 << 5) means "constructed", and 4 is
|
||||
// the DirectoryName tag.
|
||||
return TLV((2 << 6) | (1 << 5) | 4, name);
|
||||
}
|
||||
|
||||
inline ByteString IPAddress() {
|
||||
// (2 << 6) means "context-specific", 7 is the GeneralName tag.
|
||||
return TLV((2 << 6) | 7, ByteString());
|
||||
}
|
||||
|
||||
template <size_t L>
|
||||
inline ByteString IPAddress(const uint8_t (&bytes)[L]) {
|
||||
// (2 << 6) means "context-specific", 7 is the GeneralName tag.
|
||||
return TLV((2 << 6) | 7, ByteString(bytes, L));
|
||||
}
|
||||
|
||||
// Names should be zero or more GeneralNames, like DNSName and IPAddress return,
|
||||
// concatenated together.
|
||||
//
|
||||
// CreatedEncodedSubjectAltName(ByteString()) results in a SAN with an empty
|
||||
// sequence. CreateEmptyEncodedSubjectName() results in a SAN without any
|
||||
// sequence.
|
||||
ByteString CreateEncodedSubjectAltName(const ByteString& names);
|
||||
ByteString CreateEncodedEmptySubjectAltName();
|
||||
|
||||
class TestKeyPair {
|
||||
public:
|
||||
virtual ~TestKeyPair() {}
|
||||
|
||||
const TestPublicKeyAlgorithm publicKeyAlg;
|
||||
|
||||
// The DER encoding of the entire SubjectPublicKeyInfo structure. This is
|
||||
// what is encoded in certificates.
|
||||
const ByteString subjectPublicKeyInfo;
|
||||
|
||||
// The DER encoding of subjectPublicKeyInfo.subjectPublicKey. This is what is
|
||||
// hashed to create CertIDs for OCSP.
|
||||
const ByteString subjectPublicKey;
|
||||
|
||||
virtual Result SignData(const ByteString& tbs,
|
||||
const TestSignatureAlgorithm& signatureAlgorithm,
|
||||
/*out*/ ByteString& signature) const = 0;
|
||||
|
||||
virtual TestKeyPair* Clone() const = 0;
|
||||
|
||||
protected:
|
||||
TestKeyPair(const TestPublicKeyAlgorithm& publicKeyAlg,
|
||||
const ByteString& spk);
|
||||
TestKeyPair(const TestKeyPair&) = delete;
|
||||
void operator=(const TestKeyPair&) = delete;
|
||||
};
|
||||
|
||||
TestKeyPair* CloneReusedKeyPair();
|
||||
TestKeyPair* GenerateKeyPair();
|
||||
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 TestDigestBuf(Input item, DigestAlgorithm digestAlg,
|
||||
/*out*/ uint8_t* digestBuf, size_t digestBufLen);
|
||||
|
||||
// Replace one substring in item with another of the same length, but only if
|
||||
// the substring was found exactly once. The "same length" restriction is
|
||||
// useful for avoiding invalidating lengths encoded within the item. The
|
||||
// "only once" restriction is helpful for avoiding making accidental changes.
|
||||
//
|
||||
// The string to search for must be 8 or more bytes long so that it is
|
||||
// extremely unlikely that there will ever be any false positive matches
|
||||
// in digital signatures, keys, hashes, etc.
|
||||
Result TamperOnce(/*in/out*/ ByteString& item, const ByteString& from,
|
||||
const ByteString& to);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Encode Certificates
|
||||
|
||||
enum Version { v1 = 0, v2 = 1, v3 = 2 };
|
||||
|
||||
// signature is assumed to be the DER encoding of an AlgorithmIdentifer. It is
|
||||
// put into the signature field of the TBSCertificate. In most cases, it will
|
||||
// be the same as signatureAlgorithm, which is the algorithm actually used
|
||||
// to sign the certificate.
|
||||
// serialNumber is assumed to be the DER encoding of an INTEGER.
|
||||
//
|
||||
// If extensions is null, then no extensions will be encoded. Otherwise,
|
||||
// extensions must point to an array of ByteStrings, terminated with an empty
|
||||
// ByteString. (If the first item of the array is empty then an empty
|
||||
// Extensions sequence will be encoded.)
|
||||
ByteString CreateEncodedCertificate(
|
||||
long version, const TestSignatureAlgorithm& signature,
|
||||
const ByteString& serialNumber, const ByteString& issuerNameDER,
|
||||
time_t notBefore, time_t notAfter, const ByteString& subjectNameDER,
|
||||
const TestKeyPair& subjectKeyPair,
|
||||
/*optional*/ const ByteString* extensions, const TestKeyPair& issuerKeyPair,
|
||||
const TestSignatureAlgorithm& signatureAlgorithm);
|
||||
|
||||
ByteString CreateEncodedSerialNumber(long value);
|
||||
|
||||
enum class Critical { No = 0, Yes = 1 };
|
||||
|
||||
ByteString CreateEncodedBasicConstraints(
|
||||
bool isCA,
|
||||
/*optional in*/ const long* pathLenConstraint, Critical critical);
|
||||
|
||||
// Creates a DER-encoded extKeyUsage extension with one EKU OID.
|
||||
ByteString CreateEncodedEKUExtension(Input eku, Critical critical);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Encode OCSP responses
|
||||
|
||||
class OCSPResponseExtension final {
|
||||
public:
|
||||
OCSPResponseExtension();
|
||||
|
||||
ByteString id;
|
||||
bool critical;
|
||||
ByteString value;
|
||||
OCSPResponseExtension* next;
|
||||
};
|
||||
|
||||
class OCSPResponseContext final {
|
||||
public:
|
||||
OCSPResponseContext(const CertID& certID, std::time_t time);
|
||||
|
||||
const CertID& certID;
|
||||
// TODO(bug 980538): add a way to specify what certificates are included.
|
||||
|
||||
// The fields below are in the order that they appear in an OCSP response.
|
||||
|
||||
enum OCSPResponseStatus {
|
||||
successful = 0,
|
||||
malformedRequest = 1,
|
||||
internalError = 2,
|
||||
tryLater = 3,
|
||||
// 4 is not used
|
||||
sigRequired = 5,
|
||||
unauthorized = 6,
|
||||
};
|
||||
uint8_t responseStatus; // an OCSPResponseStatus or an invalid value
|
||||
bool skipResponseBytes; // If true, don't include responseBytes
|
||||
|
||||
// responderID
|
||||
ByteString signerNameDER; // If set, responderID will use the byName
|
||||
// form; otherwise responderID will use the
|
||||
// byKeyHash form.
|
||||
|
||||
std::time_t producedAt;
|
||||
|
||||
// SingleResponse extensions (for the certID given in the constructor).
|
||||
OCSPResponseExtension* singleExtensions;
|
||||
// ResponseData extensions.
|
||||
OCSPResponseExtension* responseExtensions;
|
||||
bool includeEmptyExtensions; // If true, include the extension wrapper
|
||||
// regardless of if there are any actual
|
||||
// extensions.
|
||||
ScopedTestKeyPair signerKeyPair;
|
||||
TestSignatureAlgorithm signatureAlgorithm;
|
||||
bool badSignature; // If true, alter the signature to fail verification
|
||||
const ByteString* certs; // optional; array terminated by an empty string
|
||||
|
||||
// The following fields are on a per-SingleResponse basis. In the future we
|
||||
// may support including multiple SingleResponses per response.
|
||||
enum CertStatus {
|
||||
good = 0,
|
||||
revoked = 1,
|
||||
unknown = 2,
|
||||
};
|
||||
uint8_t certStatus; // CertStatus or an invalid value
|
||||
std::time_t revocationTime; // For certStatus == revoked
|
||||
std::time_t thisUpdate;
|
||||
std::time_t nextUpdate;
|
||||
bool includeNextUpdate;
|
||||
};
|
||||
|
||||
ByteString CreateEncodedOCSPResponse(OCSPResponseContext& context);
|
||||
}
|
||||
}
|
||||
} // namespace mozilla::pkix::test
|
||||
|
||||
#endif // mozilla_pkix_test_pkixtestutil_h
|
||||
Loading…
Add table
Add a link
Reference in a new issue