in src/NuGet.Core/NuGet.Packaging/Signing/Utility/SignatureUtility.cs [362:569]
private static IX509CertificateChain GetCertificates(
SignedCms signedCms,
SignerInfo signerInfo,
SigningCertificateRequirement signingCertificateRequirement,
bool isIssuerSerialRequired,
Errors errors,
SigningSpecifications signingSpecifications,
CertificateType certificateType,
bool includeChain)
{
if (signedCms == null)
{
throw new ArgumentNullException(nameof(signedCms));
}
if (signingSpecifications == null)
{
throw new ArgumentNullException(nameof(signingSpecifications));
}
if (signerInfo.Certificate == null)
{
throw new SignatureException(errors.NoCertificate, errors.NoCertificateString);
}
/*
The signing-certificate and signing-certificate-v2 attributes are described in RFC 2634 and RFC 5035.
Timestamps
--------------------------------------------------
RFC 3161 requires the signing-certificate attribute. The RFC 5816 update introduces the newer
signing-certificate-v2 attribute, which may replace or, for backwards compatibility, be present
alongside the older signing-certificate attribute.
The issuerSerial field is not required, but should be validated if present.
Author and repository signatures
--------------------------------------------------
RFC 5126 (CAdES) requires that exactly one of either of these attributes be present, and also requires that
the issuerSerial field be present.
Validation
--------------------------------------------------
For author and repository signatures:
* the signing-certificate attribute must not be present
* the signing-certificate-v2 attribute be present
* the issuerSerial field must be present
References:
"Signing Certificate Attribute Definition", RFC 2634 section 5.4 (https://tools.ietf.org/html/rfc2634#section-5.4)
"Certificate Identification", RFC 2634 section 5.4 (https://tools.ietf.org/html/rfc2634#section-5.4.1)
"Enhanced Security Services (ESS) Update: Adding CertID Algorithm Agility", RFC 5035 (https://tools.ietf.org/html/rfc5035)
"Request Format", RFC 3161 section 2.4.1 (https://tools.ietf.org/html/rfc3161#section-2.4.1)
"Signature of Time-Stamp Token", RFC 5816 section 2.2.1 (https://tools.ietf.org/html/rfc5816#section-2.2.1)
"Signing Certificate Reference Attributes", RFC 5126 section 5.7.3 (https://tools.ietf.org/html/rfc5126.html#section-5.7.3)
"ESS signing-certificate Attribute Definition", RFC 5126 section 5.7.3.1 (https://tools.ietf.org/html/rfc5126.html#section-5.7.3.1)
"ESS signing-certificate-v2 Attribute Definition", RFC 5126 section 5.7.3.2 (https://tools.ietf.org/html/rfc5126.html#section-5.7.3.2)
*/
const string signingCertificateName = "signing-certificate";
const string signingCertificateV2Name = "signing-certificate-v2";
CryptographicAttributeObject signingCertificateAttribute = null;
CryptographicAttributeObject signingCertificateV2Attribute = null;
foreach (var attribute in signerInfo.SignedAttributes)
{
switch (attribute.Oid.Value)
{
case Oids.SigningCertificate:
if (signingCertificateAttribute != null)
{
throw new SignatureException(
errors.InvalidSignature,
string.Format(
CultureInfo.CurrentCulture,
Strings.MultipleAttributesDisallowed,
signingCertificateName));
}
if (attribute.Values.Count != 1)
{
throw new SignatureException(
errors.InvalidSignature,
string.Format(
CultureInfo.CurrentCulture,
Strings.ExactlyOneAttributeValueRequired,
signingCertificateName));
}
signingCertificateAttribute = attribute;
break;
case Oids.SigningCertificateV2:
if (signingCertificateV2Attribute != null)
{
throw new SignatureException(
errors.InvalidSignature,
string.Format(
CultureInfo.CurrentCulture,
Strings.MultipleAttributesDisallowed,
signingCertificateV2Name));
}
if (attribute.Values.Count != 1)
{
throw new SignatureException(
errors.InvalidSignature,
string.Format(
CultureInfo.CurrentCulture,
Strings.ExactlyOneAttributeValueRequired,
signingCertificateV2Name));
}
signingCertificateV2Attribute = attribute;
break;
}
}
switch (signingCertificateRequirement)
{
case SigningCertificateRequirement.OnlyV2:
{
if (signingCertificateAttribute != null)
{
throw new SignatureException(errors.InvalidSignature, Strings.SigningCertificateAttributeMustNotBePresent);
}
if (signingCertificateV2Attribute == null)
{
throw new SignatureException(
errors.InvalidSignature,
string.Format(CultureInfo.CurrentCulture,
Strings.ExactlyOneAttributeRequired,
signingCertificateV2Name));
}
}
break;
case SigningCertificateRequirement.EitherOrBoth:
if (signingCertificateAttribute == null && signingCertificateV2Attribute == null)
{
throw new SignatureException(errors.InvalidSignature, Strings.SigningCertificateV1OrV2AttributeMustBePresent);
}
break;
}
if (signingCertificateV2Attribute != null)
{
var reader = CreateDerSequenceReader(signingCertificateV2Attribute);
var signingCertificateV2 = SigningCertificateV2.Read(reader);
if (signingCertificateV2.Certificates.Count == 0)
{
throw new SignatureException(errors.InvalidSignature, Strings.SigningCertificateV2Invalid);
}
foreach (var essCertIdV2 in signingCertificateV2.Certificates)
{
if (!signingSpecifications.AllowedHashAlgorithmOids.Contains(
essCertIdV2.HashAlgorithm.Algorithm.Value,
StringComparer.Ordinal))
{
throw new SignatureException(errors.InvalidSignature, Strings.SigningCertificateV2UnsupportedHashAlgorithm);
}
}
if (!IsMatch(signerInfo.Certificate, signingCertificateV2.Certificates[0], errors, isIssuerSerialRequired))
{
throw new SignatureException(errors.InvalidSignature, Strings.SigningCertificateV2CertificateNotFound);
}
}
if (signingCertificateAttribute != null)
{
var reader = CreateDerSequenceReader(signingCertificateAttribute);
var signingCertificate = SigningCertificate.Read(reader);
if (signingCertificate.Certificates.Count == 0)
{
throw new SignatureException(errors.InvalidSignature, Strings.SigningCertificateInvalid);
}
if (!IsMatch(signerInfo.Certificate, signingCertificate.Certificates[0]))
{
throw new SignatureException(errors.InvalidSignature, Strings.SigningCertificateCertificateNotFound);
}
}
IX509CertificateChain certificates = GetCertificateChain(
signerInfo.Certificate,
signedCms.Certificates,
certificateType,
includeChain);
if (certificates == null || certificates.Count == 0)
{
certificates?.Dispose();
throw new SignatureException(errors.ChainBuildingFailed, Strings.CertificateChainBuildFailed);
}
return certificates;
}