createOCSPResponse static method
Uint8List
createOCSPResponse({
- required AsymmetricKeyPair<
PublicKey, PrivateKey> responderKeyPair, - required AsymmetricKeyPair<
PublicKey, PrivateKey> issuerKeyPair, - required Uint8List requestBytes,
- required OcspEntryStatus checkStatus(
- BigInt serial
Implementation
static Uint8List createOCSPResponse({
required AsymmetricKeyPair<PublicKey, PrivateKey> responderKeyPair,
required AsymmetricKeyPair<PublicKey, PrivateKey> issuerKeyPair,
required Uint8List requestBytes,
required OcspEntryStatus Function(BigInt serial) checkStatus,
}) {
final parser = ASN1Parser(requestBytes);
final reqSeq = parser.nextObject() as ASN1Sequence;
final tbsReq = reqSeq.elements[0] as ASN1Sequence;
var reqListIndex = 0;
while (reqListIndex < tbsReq.elements.length &&
tbsReq.elements[reqListIndex] is! ASN1Sequence) {
reqListIndex++;
}
final requestList = tbsReq.elements[reqListIndex] as ASN1Sequence;
Uint8List? nonce;
for (final el in tbsReq.elements) {
if (el.tag == 0xA2) {
// [2] explicit Extensions
final extSeq = el as ASN1Sequence;
if (extSeq.elements.isNotEmpty) {
final inner = extSeq.elements[0] as ASN1Sequence;
for (final ext in inner.elements) {
final seq = ext as ASN1Sequence;
final oidObj = seq.elements[0] as ASN1ObjectIdentifier;
final nonceOid = ASN1ObjectIdentifier.fromComponentString(
'1.3.6.1.5.5.7.48.1.2');
bool match = true;
if (oidObj.encodedBytes.length != nonceOid.encodedBytes.length) {
match = false;
} else {
for (int i = 0; i < oidObj.encodedBytes.length; i++) {
if (oidObj.encodedBytes[i] != nonceOid.encodedBytes[i]) {
match = false;
break;
}
}
}
if (match) {
nonce = (seq.elements[1] as dynamic).valueBytes();
}
}
}
}
}
final responses = ASN1Sequence();
for (final req in requestList.elements) {
final reqSeq = req as ASN1Sequence;
final certId = reqSeq.elements[0] as ASN1Sequence;
final serialC = certId.elements[3] as ASN1Integer;
final serial = serialC.valueAsBigInteger;
final statusInfo = checkStatus(serial);
final singleResp = ASN1Sequence();
singleResp.add(certId);
if (statusInfo.status == 0) {
// Good
singleResp.add(ASN1Null(tag: 0x80));
} else if (statusInfo.status == 1) {
// Revoked
final revInfo = ASN1Sequence(tag: 0xA1);
revInfo.add(ASN1GeneralizedTime(
statusInfo.revocationTime ?? DateTime.now(),
tag: 0x18));
if (statusInfo.revocationReason != null) {
final enumVal =
ASN1Integer(BigInt.from(statusInfo.revocationReason!), tag: 0xA0);
revInfo.add(enumVal);
}
singleResp.add(revInfo);
} else {
// Unknown
singleResp.add(ASN1Null(tag: 0x82));
}
singleResp.add(
ASN1GeneralizedTime(statusInfo.thisUpdate ?? DateTime.now().toUtc()));
if (statusInfo.nextUpdate != null) {
final nextWrapper = ASN1Sequence(tag: 0xA0);
nextWrapper.add(ASN1GeneralizedTime(statusInfo.nextUpdate!));
singleResp.add(nextWrapper);
}
responses.add(singleResp);
}
final responseData = ASN1Sequence();
final responderKeyHash = _calculateSha1(
_encodePublicKeyInfo(responderKeyPair.publicKey as RSAPublicKey));
final rid = ASN1OctetString(responderKeyHash, tag: 0x82);
responseData.add(rid);
responseData.add(ASN1GeneralizedTime(DateTime.now().toUtc()));
responseData.add(responses);
if (nonce != null) {
final extSeq = ASN1Sequence();
final nonceExt = ASN1Sequence();
nonceExt.add(
ASN1ObjectIdentifier.fromComponentString('1.3.6.1.5.5.7.48.1.2'));
nonceExt.add(ASN1OctetString(nonce));
extSeq.add(nonceExt);
final extWrapper = ASN1Sequence(tag: 0xA1);
extWrapper.add(extSeq);
responseData.add(extWrapper);
}
final signature = signData(responseData.encodedBytes,
responderKeyPair.privateKey as RSAPrivateKey);
final basicResp = ASN1Sequence();
basicResp.add(responseData);
basicResp.add(createAlgorithmIdentifier(sha256WithRSAEncryption));
basicResp.add(ASN1BitString(signature));
final ocspResp = ASN1Sequence();
final successful = ASN1Integer(BigInt.zero, tag: 0x0A); // successful(0)
ocspResp.add(successful);
final responseBytes = ASN1Sequence(tag: 0xA0);
responseBytes
.add(ASN1ObjectIdentifier.fromComponentString('1.3.6.1.5.5.7.48.1.1'));
responseBytes.add(ASN1OctetString(basicResp.encodedBytes));
ocspResp.add(responseBytes);
return ocspResp.encodedBytes;
}