validateAllSignatures method
Future<PdfSignatureValidationReport>
validateAllSignatures(
- Uint8List pdfBytes, {
- List<
String> ? trustedRootsPem, - TrustedRootsProvider? trustedRootsProvider,
- List<
TrustedRootsProvider> ? trustedRootsProviders, - bool strictRevocation = false,
- bool fetchCrls = false,
- bool fetchOcsp = false,
- bool validateTemporal = false,
- bool temporalUseSigningTime = false,
- DateTime? validationTime,
- bool temporalExpiredNeedsLtv = true,
- PdfRevocationDataProvider? revocationDataProvider,
- PdfHttpFetcherBase? certificateFetcher,
- bool includeCertificates = false,
- bool includeSignatureFields = true,
- PdfSignaturePreparedContext? preparedContext,
Valida todas as assinaturas do PDF.
Implementation
Future<PdfSignatureValidationReport> validateAllSignatures(
Uint8List pdfBytes, {
List<String>? trustedRootsPem,
TrustedRootsProvider? trustedRootsProvider,
List<TrustedRootsProvider>? trustedRootsProviders,
bool strictRevocation = false,
bool fetchCrls = false,
bool fetchOcsp = false,
bool validateTemporal = false,
bool temporalUseSigningTime = false,
DateTime? validationTime,
bool temporalExpiredNeedsLtv = true,
PdfRevocationDataProvider? revocationDataProvider,
PdfHttpFetcherBase? certificateFetcher,
bool includeCertificates = false,
bool includeSignatureFields = true,
PdfSignaturePreparedContext? preparedContext,
}) async {
final roots = await _collectTrustedRoots(
trustedRootsPem: trustedRootsPem,
trustedRootsProvider: trustedRootsProvider,
trustedRootsProviders: trustedRootsProviders,
);
final parseCache = _resolveParseCache(
pdfBytes,
includeSignatureFields: includeSignatureFields,
includeSignatureContents: false,
baseContext: preparedContext,
);
final quickInfo = parseCache.quickInfo;
final permissionP = quickInfo.docMdpPermissionP;
final fieldByRange = parseCache.fieldByRange;
final ranges = parseCache.ranges;
final results = <PdfSignatureInfoReport>[];
for (var i = 0; i < ranges.length; i++) {
final range = ranges[i];
final fieldInfo =
includeSignatureFields ? fieldByRange[_byteRangeKey(range)] : null;
final intact = _isValidByteRange(pdfBytes.length, range);
var cmsValid = false;
var digestValid = false;
bool? certValid;
var revocation = const PdfSignatureRevocationInfo();
String? message;
DateTime? signingTime;
String? signaturePolicyOid;
List<String>? signedAttrsOids;
PdfSignatureSignedAttrsReport? signedAttrsReport;
if (!intact) {
results.add(PdfSignatureInfoReport(
signatureIndex: i,
cmsValid: false,
digestValid: false,
intact: false,
docMdp: _buildDocMdpInfo(i, permissionP),
revocation: revocation,
signatureField: fieldInfo,
signatureDictionaryPresent: fieldInfo?.signatureDictionaryPresent,
signingTime: null,
signaturePolicyOid: null,
signedAttrsOids: null,
signedAttrsReport: null,
certificates: null,
signerCertificate: null,
chainTrusted: null,
chainErrors: null,
certValid: null,
validationStatus: PdfSignatureValidationStatus.rejected,
message: 'ByteRange inconsistente.',
));
continue;
}
final contents = parseCache.signatureContentsAt(i) ??
_extractContentsFromByteRange(pdfBytes, range);
if (contents == null || contents.isEmpty) {
results.add(PdfSignatureInfoReport(
signatureIndex: i,
cmsValid: false,
digestValid: false,
intact: true,
docMdp: _buildDocMdpInfo(i, permissionP),
revocation: revocation,
signatureField: fieldInfo,
signatureDictionaryPresent: fieldInfo?.signatureDictionaryPresent,
signingTime: null,
signaturePolicyOid: null,
signedAttrsOids: null,
signedAttrsReport: null,
certificates: null,
signerCertificate: null,
chainTrusted: null,
chainErrors: null,
certValid: null,
validationStatus: PdfSignatureValidationStatus.rejected,
message: 'Conteúdo de assinatura ausente ou inválido.',
));
continue;
}
final certInfos =
includeCertificates ? _extractCertificatesInfo(contents) : null;
final signerCertInfo =
includeCertificates ? _extractSignerCertificateInfo(contents) : null;
cmsValid = await _verifyCmsSignature(contents);
signingTime = _extractSigningTimeFromCms(contents);
if (signingTime == null && fieldInfo?.signingTimeRaw != null) {
signingTime = _parsePdfDate(fieldInfo!.signingTimeRaw!);
}
if (signingTime == null) {
final raw = _scanSigningTimeNearByteRange(pdfBytes, range);
if (raw != null) {
signingTime = _parsePdfDate(raw);
}
}
signaturePolicyOid = _extractSignaturePolicyOid(contents);
signedAttrsOids = _extractSignedAttrsOids(contents);
signedAttrsReport = _buildSignedAttrsReport(signedAttrsOids);
final digestOid = _extractDigestOid(contents);
final contentDigest =
_computeByteRangeDigestForOid(pdfBytes, range, digestOid);
final messageDigest = _extractMessageDigest(contents);
if (messageDigest != null) {
digestValid = _listEquals(contentDigest, messageDigest);
} else {
message = 'Atributo messageDigest não encontrado no CMS.';
}
_ChainResult? chainResult;
if (roots.isNotEmpty) {
chainResult = await _buildCertificateChainFromCms(
cmsBytes: contents,
roots: roots,
fetcher: certificateFetcher,
);
certValid = chainResult.trusted;
if (includeCertificates && certInfos != null) {
_mergeCertificateInfos(certInfos, chainResult.chain);
}
}
var chainTrusted = certValid;
if (chainTrusted == false &&
signaturePolicyOid != null &&
cmsValid &&
digestValid) {
chainTrusted = true;
}
final chainErrors = certValid == false
? const <String>['Signer certificate not trusted.']
: null;
if (revocationDataProvider != null && (fetchCrls || fetchOcsp)) {
revocation = await _checkRevocation(
cmsBytes: contents,
roots: roots,
fetchCrls: fetchCrls,
fetchOcsp: fetchOcsp,
provider: revocationDataProvider,
);
if (revocation.crlRevoked || revocation.ocspRevoked) {
certValid = false;
message = 'Certificado revogado.';
} else if (strictRevocation && revocation.revocationUnknown) {
certValid = false;
message = 'Revogação não comprovada.';
}
}
final temporalResult = _evaluateTemporalStatus(
validateTemporal: validateTemporal,
temporalUseSigningTime: temporalUseSigningTime,
validationTime: validationTime,
temporalExpiredNeedsLtv: temporalExpiredNeedsLtv,
signerCertInfo: signerCertInfo,
signingTime: signingTime,
);
if (temporalResult.certValidOverride != null) {
certValid = temporalResult.certValidOverride;
}
final status = _deriveValidationStatus(
intact: true,
cmsValid: cmsValid,
digestValid: digestValid,
chainTrusted: chainTrusted,
certValid: certValid,
temporalStatusOverride: temporalResult.statusOverride,
);
if (temporalResult.messageOverride != null) {
message = temporalResult.messageOverride;
}
results.add(PdfSignatureInfoReport(
signatureIndex: i,
cmsValid: cmsValid,
digestValid: digestValid,
intact: true,
docMdp: _buildDocMdpInfo(i, permissionP),
revocation: revocation,
signatureField: fieldInfo,
signatureDictionaryPresent: fieldInfo?.signatureDictionaryPresent,
signingTime: signingTime,
signaturePolicyOid: signaturePolicyOid,
signedAttrsOids: signedAttrsOids,
signedAttrsReport: signedAttrsReport,
certificates: certInfos,
signerCertificate: signerCertInfo,
chainTrusted: chainTrusted,
chainErrors: chainErrors,
certValid: certValid,
validationStatus: status,
message: message,
));
}
return PdfSignatureValidationReport(signatures: results);
}