public static void AddFirstCounterSigner_NoSignature_NoPrivateKey() { SignedCms cms = new SignedCms(); cms.Decode(SignedDocuments.RsaPkcs1OneSignerIssuerAndSerialNumber); SignerInfo firstSigner = cms.SignerInfos[0]; using (X509Certificate2 cert = Certificates.RSAKeyTransferCapi1.GetCertificate()) { Action sign = () => firstSigner.ComputeCounterSignature( new CmsSigner( SubjectIdentifierType.NoSignature, cert) { IncludeOption = X509IncludeOption.None, }); if (PlatformDetection.IsFullFramework) { Assert.ThrowsAny <CryptographicException>(sign); } else { sign(); cms.CheckHash(); Assert.ThrowsAny <CryptographicException>(() => cms.CheckSignature(true)); firstSigner.CheckSignature(true); } } }
public static void AddFirstCounterSigner_NoSignature() { SignedCms cms = new SignedCms(); cms.Decode(SignedDocuments.RsaPkcs1OneSignerIssuerAndSerialNumber); SignerInfo firstSigner = cms.SignerInfos[0]; // A certificate shouldn't really be required here, but on .NET Framework // it will prompt for the counter-signer's certificate if it's null, // even if the signature type is NoSignature. using (X509Certificate2 cert = Certificates.RSAKeyTransferCapi1.TryGetCertificateWithPrivateKey()) { firstSigner.ComputeCounterSignature( new CmsSigner( SubjectIdentifierType.NoSignature, cert) { IncludeOption = X509IncludeOption.None, }); } Assert.ThrowsAny <CryptographicException>(() => cms.CheckSignature(true)); cms.CheckHash(); byte[] encoded = cms.Encode(); cms = new SignedCms(); cms.Decode(encoded); Assert.ThrowsAny <CryptographicException>(() => cms.CheckSignature(true)); cms.CheckHash(); firstSigner = cms.SignerInfos[0]; firstSigner.CheckSignature(verifySignatureOnly: true); Assert.ThrowsAny <CryptographicException>(() => firstSigner.CheckHash()); SignerInfo firstCounterSigner = firstSigner.CounterSignerInfos[0]; Assert.ThrowsAny <CryptographicException>(() => firstCounterSigner.CheckSignature(true)); if (PlatformDetection.IsFullFramework) { // NetFX's CheckHash only looks at top-level SignerInfos to find the // crypt32 CMS signer ID, so it fails on any check from a countersigner. Assert.ThrowsAny <CryptographicException>(() => firstCounterSigner.CheckHash()); } else { firstCounterSigner.CheckHash(); } }
public static void AddCounterSignerToUnsortedAttributeSignature() { SignedCms cms = new SignedCms(); cms.Decode(SignedDocuments.DigiCertTimeStampToken); // Assert.NoThrows cms.CheckSignature(true); SignerInfoCollection signers = cms.SignerInfos; Assert.Equal(1, signers.Count); SignerInfo signerInfo = signers[0]; using (X509Certificate2 cert = Certificates.RSAKeyTransferCapi1.TryGetCertificateWithPrivateKey()) { signerInfo.ComputeCounterSignature( new CmsSigner( SubjectIdentifierType.IssuerAndSerialNumber, cert)); signerInfo.ComputeCounterSignature( new CmsSigner( SubjectIdentifierType.SubjectKeyIdentifier, cert)); } // Assert.NoThrows cms.CheckSignature(true); byte[] exported = cms.Encode(); cms = new SignedCms(); cms.Decode(exported); // Assert.NoThrows cms.CheckSignature(true); }
public static void AddCounterSigner_DuplicateCert_RSA() { SignedCms cms = new SignedCms(); cms.Decode(SignedDocuments.RsaPkcs1OneSignerIssuerAndSerialNumber); Assert.Single(cms.Certificates); SignerInfo firstSigner = cms.SignerInfos[0]; Assert.Empty(firstSigner.CounterSignerInfos); Assert.Empty(firstSigner.UnsignedAttributes); using (X509Certificate2 signerCert = Certificates.RSAKeyTransferCapi1.TryGetCertificateWithPrivateKey()) { CmsSigner signer = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, signerCert); firstSigner.ComputeCounterSignature(signer); } Assert.Empty(firstSigner.CounterSignerInfos); Assert.Empty(firstSigner.UnsignedAttributes); SignerInfo firstSigner2 = cms.SignerInfos[0]; Assert.Single(firstSigner2.CounterSignerInfos); Assert.Single(firstSigner2.UnsignedAttributes); SignerInfo counterSigner = firstSigner2.CounterSignerInfos[0]; Assert.Equal(SubjectIdentifierType.IssuerAndSerialNumber, counterSigner.SignerIdentifier.Type); // On NetFx there will be two attributes, because Windows emits the // content-type attribute even for counter-signers. int expectedAttrCount = 1; // One of them is a V3 signer. #if netfx expectedAttrCount = 2; #endif Assert.Equal(expectedAttrCount, counterSigner.SignedAttributes.Count); Assert.Equal(Oids.MessageDigest, counterSigner.SignedAttributes[expectedAttrCount - 1].Oid.Value); Assert.Equal(firstSigner2.Certificate, counterSigner.Certificate); Assert.Single(cms.Certificates); counterSigner.CheckSignature(true); firstSigner2.CheckSignature(true); cms.CheckSignature(true); }
public static void AddCounterSigner_RSA(SubjectIdentifierType identifierType) { SignedCms cms = new SignedCms(); cms.Decode(SignedDocuments.RsaPkcs1OneSignerIssuerAndSerialNumber); Assert.Single(cms.Certificates); SignerInfo firstSigner = cms.SignerInfos[0]; Assert.Empty(firstSigner.CounterSignerInfos); Assert.Empty(firstSigner.UnsignedAttributes); using (X509Certificate2 signerCert = Certificates.RSA2048SignatureOnly.TryGetCertificateWithPrivateKey()) { CmsSigner signer = new CmsSigner(identifierType, signerCert); firstSigner.ComputeCounterSignature(signer); } Assert.Empty(firstSigner.CounterSignerInfos); Assert.Empty(firstSigner.UnsignedAttributes); SignerInfo firstSigner2 = cms.SignerInfos[0]; Assert.Single(firstSigner2.CounterSignerInfos); Assert.Single(firstSigner2.UnsignedAttributes); SignerInfo counterSigner = firstSigner2.CounterSignerInfos[0]; Assert.Equal(identifierType, counterSigner.SignerIdentifier.Type); // On .NET Framework there will be two attributes, because Windows emits the // content-type attribute even for counter-signers. int expectedCount = 1; #if NETFRAMEWORK expectedCount = 2; #endif Assert.Equal(expectedCount, counterSigner.SignedAttributes.Count); Assert.Equal(Oids.MessageDigest, counterSigner.SignedAttributes[expectedCount - 1].Oid.Value); Assert.NotEqual(firstSigner2.Certificate, counterSigner.Certificate); Assert.Equal(2, cms.Certificates.Count); counterSigner.CheckSignature(true); firstSigner2.CheckSignature(true); cms.CheckSignature(true); }
private static void AddSecondCounterSignature_NoSignature(bool withCertificate, bool addExtraCert) { X509Certificate2Collection certs; SignedCms cms = new SignedCms(); cms.Decode(SignedDocuments.RsaPkcs1OneSignerIssuerAndSerialNumber); SignerInfo firstSigner = cms.SignerInfos[0]; using (X509Certificate2 cert = Certificates.RSAKeyTransferCapi1.TryGetCertificateWithPrivateKey()) using (X509Certificate2 cert2 = Certificates.DHKeyAgree1.GetCertificate()) { firstSigner.ComputeCounterSignature( new CmsSigner(cert) { IncludeOption = X509IncludeOption.None, }); CmsSigner counterSigner; if (withCertificate) { counterSigner = new CmsSigner(SubjectIdentifierType.NoSignature, cert); } else { counterSigner = new CmsSigner(SubjectIdentifierType.NoSignature); } if (addExtraCert) { counterSigner.Certificates.Add(cert2); } firstSigner.ComputeCounterSignature(counterSigner); certs = cms.Certificates; if (addExtraCert) { Assert.Equal(2, certs.Count); Assert.NotEqual(cert2.RawData, certs[0].RawData); Assert.Equal(cert2.RawData, certs[1].RawData); } else { Assert.Equal(1, certs.Count); Assert.NotEqual(cert2.RawData, certs[0].RawData); } } Assert.ThrowsAny <CryptographicException>(() => cms.CheckSignature(true)); cms.CheckHash(); byte[] encoded = cms.Encode(); cms = new SignedCms(); cms.Decode(encoded); Assert.ThrowsAny <CryptographicException>(() => cms.CheckSignature(true)); cms.CheckHash(); firstSigner = cms.SignerInfos[0]; firstSigner.CheckSignature(verifySignatureOnly: true); Assert.ThrowsAny <CryptographicException>(() => firstSigner.CheckHash()); // The NoSignature CounterSigner sorts first. SignerInfo firstCounterSigner = firstSigner.CounterSignerInfos[0]; Assert.Equal(SubjectIdentifierType.NoSignature, firstCounterSigner.SignerIdentifier.Type); Assert.ThrowsAny <CryptographicException>(() => firstCounterSigner.CheckSignature(true)); if (PlatformDetection.IsFullFramework) { // NetFX's CheckHash only looks at top-level SignerInfos to find the // crypt32 CMS signer ID, so it fails on any check from a countersigner. Assert.ThrowsAny <CryptographicException>(() => firstCounterSigner.CheckHash()); } else { firstCounterSigner.CheckHash(); } certs = cms.Certificates; if (addExtraCert) { Assert.Equal(2, certs.Count); Assert.Equal("CN=DfHelleKeyAgreement1", certs[1].SubjectName.Name); } else { Assert.Equal(1, certs.Count); } Assert.Equal("CN=RSAKeyTransferCapi1", certs[0].SubjectName.Name); }
public static void AddCounterSigner_ECDSA(SubjectIdentifierType identifierType, string digestOid) { SignedCms cms = new SignedCms(); cms.Decode(SignedDocuments.RsaPkcs1OneSignerIssuerAndSerialNumber); Assert.Single(cms.Certificates); SignerInfo firstSigner = cms.SignerInfos[0]; Assert.Empty(firstSigner.CounterSignerInfos); Assert.Empty(firstSigner.UnsignedAttributes); using (X509Certificate2 signerCert = Certificates.ECDsaP256Win.TryGetCertificateWithPrivateKey()) { CmsSigner signer = new CmsSigner(identifierType, signerCert); signer.IncludeOption = X509IncludeOption.EndCertOnly; signer.DigestAlgorithm = new Oid(digestOid, digestOid); firstSigner.ComputeCounterSignature(signer); } Assert.Empty(firstSigner.CounterSignerInfos); Assert.Empty(firstSigner.UnsignedAttributes); SignerInfo firstSigner2 = cms.SignerInfos[0]; Assert.Single(firstSigner2.CounterSignerInfos); Assert.Single(firstSigner2.UnsignedAttributes); Assert.Single(cms.SignerInfos); Assert.Equal(2, cms.Certificates.Count); SignerInfo counterSigner = firstSigner2.CounterSignerInfos[0]; int expectedVersion = identifierType == SubjectIdentifierType.IssuerAndSerialNumber ? 1 : 3; Assert.Equal(expectedVersion, counterSigner.Version); // On NetFx there will be two attributes, because Windows emits the // content-type attribute even for counter-signers. int expectedCount = 1; #if netfx expectedCount = 2; #endif Assert.Equal(expectedCount, counterSigner.SignedAttributes.Count); Assert.Equal(Oids.MessageDigest, counterSigner.SignedAttributes[expectedCount - 1].Oid.Value); Assert.NotEqual(firstSigner2.Certificate, counterSigner.Certificate); Assert.Equal(2, cms.Certificates.Count); #if netcoreapp byte[] signature = counterSigner.GetSignature(); Assert.NotEmpty(signature); // DSA PKIX signature format is a DER SEQUENCE. Assert.Equal(0x30, signature[0]); // ECDSA Oids are all under 1.2.840.10045.4. Assert.StartsWith("1.2.840.10045.4.", counterSigner.SignatureAlgorithm.Value); #endif cms.CheckSignature(true); byte[] encoded = cms.Encode(); cms.Decode(encoded); cms.CheckSignature(true); }
public static void AddCounterSigner_DSA() { SignedCms cms = new SignedCms(); cms.Decode(SignedDocuments.RsaPkcs1OneSignerIssuerAndSerialNumber); Assert.Single(cms.Certificates); SignerInfo firstSigner = cms.SignerInfos[0]; Assert.Empty(firstSigner.CounterSignerInfos); Assert.Empty(firstSigner.UnsignedAttributes); using (X509Certificate2 signerCert = Certificates.Dsa1024.TryGetCertificateWithPrivateKey()) { CmsSigner signer = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, signerCert); signer.IncludeOption = X509IncludeOption.EndCertOnly; // Best compatibility for DSA is SHA-1 (FIPS 186-2) signer.DigestAlgorithm = new Oid(Oids.Sha1, Oids.Sha1); firstSigner.ComputeCounterSignature(signer); } Assert.Empty(firstSigner.CounterSignerInfos); Assert.Empty(firstSigner.UnsignedAttributes); SignerInfo firstSigner2 = cms.SignerInfos[0]; Assert.Single(firstSigner2.CounterSignerInfos); Assert.Single(firstSigner2.UnsignedAttributes); Assert.Single(cms.SignerInfos); Assert.Equal(2, cms.Certificates.Count); SignerInfo counterSigner = firstSigner2.CounterSignerInfos[0]; Assert.Equal(1, counterSigner.Version); // On NetFx there will be two attributes, because Windows emits the // content-type attribute even for counter-signers. int expectedCount = 1; #if netfx expectedCount = 2; #endif Assert.Equal(expectedCount, counterSigner.SignedAttributes.Count); Assert.Equal(Oids.MessageDigest, counterSigner.SignedAttributes[expectedCount - 1].Oid.Value); Assert.NotEqual(firstSigner2.Certificate, counterSigner.Certificate); Assert.Equal(2, cms.Certificates.Count); #if netcoreapp byte[] signature = counterSigner.GetSignature(); Assert.NotEmpty(signature); // DSA PKIX signature format is a DER SEQUENCE. Assert.Equal(0x30, signature[0]); #endif cms.CheckSignature(true); byte[] encoded = cms.Encode(); cms.Decode(encoded); cms.CheckSignature(true); }
public static void CounterSigningReindexes() { ContentInfo content = new ContentInfo(new byte[] { 7 }); SignedCms cms = new SignedCms(content); using (X509Certificate2 cert1 = Certificates.RSA2048SignatureOnly.TryGetCertificateWithPrivateKey()) using (X509Certificate2 cert2 = Certificates.RSAKeyTransferCapi1.TryGetCertificateWithPrivateKey()) { CmsSigner signer = new CmsSigner(SubjectIdentifierType.SubjectKeyIdentifier, cert1); cms.ComputeSignature(signer); SignerProfile yellow = new SignerProfile( cert1, SubjectIdentifierType.SubjectKeyIdentifier, hasSignedAttrs: false, hasUnsignedAttrs: false, hasCounterSigners: false); AssertSignerTraits(cms.SignerInfos[0], yellow); signer.SignedAttributes.Add(new Pkcs9SigningTime()); signer.SignerIdentifierType = SubjectIdentifierType.IssuerAndSerialNumber; cms.ComputeSignature(signer); SignerProfile green = new SignerProfile( cert1, SubjectIdentifierType.IssuerAndSerialNumber, hasSignedAttrs: true, hasUnsignedAttrs: false, hasCounterSigners: false); // No reordering. 0 stayed 0, new entry becomes 1. AssertSignerTraits(cms.SignerInfos[0], yellow); AssertSignerTraits(cms.SignerInfos[1], green); signer = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, cert2); cms.ComputeSignature(signer); SignerProfile grey = new SignerProfile( cert2, SubjectIdentifierType.IssuerAndSerialNumber, hasSignedAttrs: false, hasUnsignedAttrs: false, hasCounterSigners: false); // No reordering. 0 stayed 0, 1 stays 1, new entry is 2. AssertSignerTraits(cms.SignerInfos[0], yellow); AssertSignerTraits(cms.SignerInfos[1], green); AssertSignerTraits(cms.SignerInfos[2], grey); CmsSigner counterSigner = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, cert1); SignerInfo toCounterSign = cms.SignerInfos[0]; toCounterSign.ComputeCounterSignature(counterSigner); // Reordering just happened. // We counter-signed the first element, so it gets bigger by ~a signerinfo, or 100% bigger. // The sizes of the three were // yellow: 311 bytes // green: 455 bytes (IssuerAndSerialNumber takes more bytes, and it has attributes) // grey: 212 bytes (1024-bit RSA signature instead of 2048-bit) // // Because yellow also contains cyan (444) bytes (then also some overhead) it has grown // to 763 bytes. So the size-sorted order (DER SET-OF sorting) is { grey, green, yellow }. // Record that yellow gained a countersigner (and thus an unsigned attribute) yellow.HasUnsignedAttrs = true; yellow.HasCounterSigners = true; SignerProfile cyan = new SignerProfile( cert1, SubjectIdentifierType.IssuerAndSerialNumber, hasSignedAttrs: true, hasUnsignedAttrs: false, hasCounterSigners: false); AssertSignerTraits(cms.SignerInfos[0], grey); AssertSignerTraits(cms.SignerInfos[1], green); AssertSignerTraits(cms.SignerInfos[2], yellow); AssertSignerTraits(cms.SignerInfos[2].CounterSignerInfos[0], cyan); counterSigner.UnsignedAttributes.Add(new Pkcs9SigningTime()); toCounterSign.ComputeCounterSignature(counterSigner); SignerProfile red = new SignerProfile( cert1, SubjectIdentifierType.IssuerAndSerialNumber, hasSignedAttrs: true, hasUnsignedAttrs: true, hasCounterSigners: false); // Since "red" has one more attribute than "cyan", but they're otherwise the same // it will sort later. AssertSignerTraits(cms.SignerInfos[0], grey); AssertSignerTraits(cms.SignerInfos[1], green); AssertSignerTraits(cms.SignerInfos[2], yellow); AssertSignerTraits(cms.SignerInfos[2].CounterSignerInfos[0], cyan); AssertSignerTraits(cms.SignerInfos[2].CounterSignerInfos[1], red); counterSigner.SignerIdentifierType = SubjectIdentifierType.SubjectKeyIdentifier; toCounterSign.ComputeCounterSignature(counterSigner); SignerProfile clear = new SignerProfile( cert1, SubjectIdentifierType.SubjectKeyIdentifier, hasSignedAttrs: true, hasUnsignedAttrs: true, hasCounterSigners: false); // By changing from IssuerAndSerialNumber to SubjectKeyIdentifier, this copy will // sort higher. It saves so many bytes, in this specific case, that it goes first. AssertSignerTraits(cms.SignerInfos[0], grey); AssertSignerTraits(cms.SignerInfos[1], green); AssertSignerTraits(cms.SignerInfos[2], yellow); AssertSignerTraits(cms.SignerInfos[2].CounterSignerInfos[0], clear); AssertSignerTraits(cms.SignerInfos[2].CounterSignerInfos[1], cyan); AssertSignerTraits(cms.SignerInfos[2].CounterSignerInfos[2], red); // Now start removing things. cms.SignerInfos[2].RemoveCounterSignature(1); // Fairly predictable. AssertSignerTraits(cms.SignerInfos[0], grey); AssertSignerTraits(cms.SignerInfos[1], green); AssertSignerTraits(cms.SignerInfos[2], yellow); AssertSignerTraits(cms.SignerInfos[2].CounterSignerInfos[0], clear); AssertSignerTraits(cms.SignerInfos[2].CounterSignerInfos[1], red); cms.SignerInfos[2].RemoveCounterSignature(1); // Fairly predictable. AssertSignerTraits(cms.SignerInfos[0], grey); AssertSignerTraits(cms.SignerInfos[1], green); AssertSignerTraits(cms.SignerInfos[2], yellow); AssertSignerTraits(cms.SignerInfos[2].CounterSignerInfos[0], clear); cms.SignerInfos[2].RemoveCounterSignature(0); // We have removed the last counter-signer. // yellow is now smaller than grey. // But the document only re-normalizes on addition. yellow.HasCounterSigners = false; yellow.HasUnsignedAttrs = false; AssertSignerTraits(cms.SignerInfos[0], grey); AssertSignerTraits(cms.SignerInfos[1], green); AssertSignerTraits(cms.SignerInfos[2], yellow); // Export/import to normalize. Everyone's back to their original size, // but they were unsorted before. { grey, yellow, green } was the right order. cms.Decode(cms.Encode()); AssertSignerTraits(cms.SignerInfos[0], grey); AssertSignerTraits(cms.SignerInfos[1], yellow); AssertSignerTraits(cms.SignerInfos[2], green); cms.SignerInfos[0].ComputeCounterSignature(counterSigner); // Move to the end of the line, Mr. Grey grey.HasUnsignedAttrs = true; grey.HasCounterSigners = true; AssertSignerTraits(cms.SignerInfos[0], yellow); AssertSignerTraits(cms.SignerInfos[1], green); AssertSignerTraits(cms.SignerInfos[2], grey); AssertSignerTraits(cms.SignerInfos[2].CounterSignerInfos[0], clear); } }