createCertificate static method
X509Certificate
createCertificate({
- required AsymmetricKeyPair<
PublicKey, PrivateKey> keyPair, - required AsymmetricKeyPair<
PublicKey, PrivateKey> issuerKeyPair, - required String subjectDn,
- required String issuerDn,
- required int serialNumber,
- BigInt? serialNumberBigInt,
- required DateTime notBefore,
- required DateTime notAfter,
- bool isCa = false,
- List<
String> ? crlUrls, - List<
String> ? ocspUrls, - List<
PkiOtherName> ? subjectAltNameOtherNames, - List<
String> ? extendedKeyUsageOids, - int? keyUsageBits,
Low-level X.509 Certificate creation.
Implementation
static X509Certificate createCertificate({
required AsymmetricKeyPair<PublicKey, PrivateKey> keyPair,
required AsymmetricKeyPair<PublicKey, PrivateKey> issuerKeyPair,
required String subjectDn,
required String issuerDn,
required int serialNumber,
BigInt? serialNumberBigInt,
required DateTime notBefore,
required DateTime notAfter,
bool isCa = false,
List<String>? crlUrls,
List<String>? ocspUrls,
List<PkiOtherName>? subjectAltNameOtherNames,
List<String>? extendedKeyUsageOids,
int? keyUsageBits,
}) {
// 1. Create TBSCertificate
final tbs = ASN1Sequence();
// Version (v3 = 2) - [0] EXPLICIT wrapping INTEGER 2
final versionWrapper = ASN1Sequence(tag: 0xA0);
versionWrapper.add(ASN1Integer(BigInt.from(2)));
tbs.add(versionWrapper);
// Serial Number
final BigInt serial = serialNumberBigInt ?? BigInt.from(serialNumber);
tbs.add(ASN1Integer(serial));
// Algorithm ID
tbs.add(createAlgorithmIdentifier(sha256WithRSAEncryption));
// Issuer
tbs.add(createName(issuerDn));
// Validity
final validity = ASN1Sequence();
validity.add(_encodeTime(notBefore));
validity.add(_encodeTime(notAfter));
tbs.add(validity);
// Subject
tbs.add(createName(subjectDn));
// Subject Public Key Info
tbs.add(createSubjectPublicKeyInfo(keyPair.publicKey as RSAPublicKey));
// Extensions
final extensions = ASN1Sequence();
// Basic Constraints
extensions.add(createExtension(
oidBasicConstraints,
createBasicConstraints(isCa),
critical: true,
));
// Key Usage
extensions.add(createExtension(
oidKeyUsage,
createKeyUsage(isCa, keyUsageBits: keyUsageBits),
critical: true,
));
// Subject Key Identifier (SKID)
final subjectKeyBytes =
_encodePublicKeyInfo(keyPair.publicKey as RSAPublicKey);
final subjectKeyId = _calculateSha1(subjectKeyBytes);
extensions.add(createExtension(
oidSubjectKeyIdentifier,
ASN1OctetString(subjectKeyId),
));
// Authority Key Identifier (AKID)
// RFC 5280: The authority key identifier extension ... MUST be present in all certificates
// ... EXCEPT ... self-signed CA certificates.
if (subjectDn != issuerDn) {
final issuerKeyBytes =
_encodePublicKeyInfo(issuerKeyPair.publicKey as RSAPublicKey);
final issuerKeyId = _calculateSha1(issuerKeyBytes);
final akiSeq = ASN1Sequence();
// keyIdentifier [0] IMPLICIT KeyIdentifier
// KeyIdentifier is OCTET STRING. Implicit tag replaces it with [0] (0x80).
final keyIdOctet = ASN1OctetString(issuerKeyId, tag: 0x80);
akiSeq.add(keyIdOctet);
extensions.add(createExtension(
oidAuthorityKeyIdentifier,
akiSeq,
));
}
if (crlUrls != null && crlUrls.isNotEmpty) {
extensions.add(createExtension(
oidCrlDistributionPoints,
createCrlDistributionPoints(crlUrls),
));
}
if (ocspUrls != null && ocspUrls.isNotEmpty) {
extensions.add(createExtension(
oidAuthorityInfoAccess,
_createAuthorityInfoAccess(ocspUrls),
));
}
if (subjectAltNameOtherNames != null &&
subjectAltNameOtherNames.isNotEmpty) {
extensions.add(createExtension(
oidSubjectAltName,
createSubjectAltName(subjectAltNameOtherNames),
));
}
if (extendedKeyUsageOids != null && extendedKeyUsageOids.isNotEmpty) {
extensions.add(createExtension(
oidExtKeyUsage,
createExtendedKeyUsage(extendedKeyUsageOids),
));
}
// Wrap extensions in [3] Explicit
final extWrapper = ASN1Sequence(tag: 0xA3);
extWrapper.add(extensions);
tbs.add(extWrapper);
// 2. Sign
final signature =
signData(tbs.encodedBytes, issuerKeyPair.privateKey as RSAPrivateKey);
// 3. Assemble Certificate
final cert = ASN1Sequence();
cert.add(tbs);
cert.add(createAlgorithmIdentifier(sha256WithRSAEncryption));
cert.add(ASN1BitString(signature));
return X509Certificate.fromDer(cert.encodedBytes);
}