internal abstract void WriteString(AsnWriter writer, string s);
internal override void WriteString(AsnWriter writer, Asn1Tag tag, string s) => writer.WriteCharacterString(tag, UniversalTagNumber.BMPString, s);
internal void Encode(AsnWriter writer, Asn1Tag tag) { writer.PushSequence(tag); // DEFAULT value handler for Version. { using (AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER)) { tmp.WriteInteger(Version); ReadOnlySpan <byte> encoded = tmp.EncodeAsSpan(); if (!encoded.SequenceEqual(DefaultVersion)) { writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 0)); writer.WriteEncodedValue(encoded); writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 0)); } } } writer.WriteInteger(SerialNumber.Span); SignatureAlgorithm.Encode(writer); // Validator for tag constraint for Issuer { if (!Asn1Tag.TryDecode(Issuer.Span, out Asn1Tag validateTag, out _) || !validateTag.HasSameClassAndValue(new Asn1Tag((UniversalTagNumber)16))) { throw new CryptographicException(); } } writer.WriteEncodedValue(Issuer.Span); Validity.Encode(writer); // Validator for tag constraint for Subject { if (!Asn1Tag.TryDecode(Subject.Span, out Asn1Tag validateTag, out _) || !validateTag.HasSameClassAndValue(new Asn1Tag((UniversalTagNumber)16))) { throw new CryptographicException(); } } writer.WriteEncodedValue(Subject.Span); SubjectPublicKeyInfo.Encode(writer); if (IssuerUniqueId.HasValue) { writer.WriteBitString(new Asn1Tag(TagClass.ContextSpecific, 1), IssuerUniqueId.Value.Span); } if (SubjectUniqueId.HasValue) { writer.WriteBitString(new Asn1Tag(TagClass.ContextSpecific, 2), SubjectUniqueId.Value.Span); } if (Extensions != null) { writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 3)); writer.PushSequence(); for (int i = 0; i < Extensions.Length; i++) { Extensions[i].Encode(writer); } writer.PopSequence(); writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 3)); } writer.PopSequence(tag); }
internal SignerInfoAsn Sign( ReadOnlyMemory <byte> data, string contentTypeOid, bool silent, out X509Certificate2Collection chainCerts) { HashAlgorithmName hashAlgorithmName = Helpers.GetDigestAlgorithm(DigestAlgorithm); IncrementalHash hasher = IncrementalHash.CreateHash(hashAlgorithmName); hasher.AppendData(data.Span); byte[] dataHash = hasher.GetHashAndReset(); SignerInfoAsn newSignerInfo = new SignerInfoAsn(); newSignerInfo.DigestAlgorithm.Algorithm = DigestAlgorithm; // If the user specified attributes (not null, count > 0) we need attributes. // If the content type is null we're counter-signing, and need the message digest attr. // If the content type is otherwise not-data we need to record it as the content-type attr. if (SignedAttributes?.Count > 0 || contentTypeOid != Oids.Pkcs7Data) { List <AttributeAsn> signedAttrs = BuildAttributes(SignedAttributes); using (var writer = new AsnWriter(AsnEncodingRules.DER)) { writer.PushSetOf(); writer.WriteOctetString(dataHash); writer.PopSetOf(); signedAttrs.Add( new AttributeAsn { AttrType = new Oid(Oids.MessageDigest, Oids.MessageDigest), AttrValues = writer.Encode(), }); } if (contentTypeOid != null) { using (var writer = new AsnWriter(AsnEncodingRules.DER)) { writer.PushSetOf(); writer.WriteObjectIdentifier(contentTypeOid); writer.PopSetOf(); signedAttrs.Add( new AttributeAsn { AttrType = new Oid(Oids.ContentType, Oids.ContentType), AttrValues = writer.Encode(), }); } } // Use the serializer/deserializer to DER-normalize the attribute order. SignedAttributesSet signedAttrsSet = new SignedAttributesSet(); signedAttrsSet.SignedAttributes = Helpers.NormalizeSet( signedAttrs.ToArray(), normalized => { AsnReader reader = new AsnReader(normalized, AsnEncodingRules.DER); hasher.AppendData(reader.PeekContentBytes().Span); }); // Since this contains user data in a context where BER is permitted, use BER. // There shouldn't be any observable difference here between BER and DER, though, // since the top level fields were written by NormalizeSet. using (AsnWriter attrsWriter = AsnSerializer.Serialize(signedAttrsSet, AsnEncodingRules.BER)) { newSignerInfo.SignedAttributes = attrsWriter.Encode(); } dataHash = hasher.GetHashAndReset(); } switch (SignerIdentifierType) { case SubjectIdentifierType.IssuerAndSerialNumber: byte[] serial = Certificate.GetSerialNumber(); Array.Reverse(serial); newSignerInfo.Sid.IssuerAndSerialNumber = new IssuerAndSerialNumberAsn { Issuer = Certificate.IssuerName.RawData, SerialNumber = serial, }; newSignerInfo.Version = 1; break; case SubjectIdentifierType.SubjectKeyIdentifier: newSignerInfo.Sid.SubjectKeyIdentifier = Certificate.GetSubjectKeyIdentifier(); newSignerInfo.Version = 3; break; case SubjectIdentifierType.NoSignature: newSignerInfo.Sid.IssuerAndSerialNumber = new IssuerAndSerialNumberAsn { Issuer = SubjectIdentifier.DummySignerEncodedValue, SerialNumber = new byte[1], }; newSignerInfo.Version = 1; break; default: Debug.Fail($"Unresolved SignerIdentifierType value: {SignerIdentifierType}"); throw new CryptographicException(); } if (UnsignedAttributes != null && UnsignedAttributes.Count > 0) { List <AttributeAsn> attrs = BuildAttributes(UnsignedAttributes); newSignerInfo.UnsignedAttributes = Helpers.NormalizeSet(attrs.ToArray()); } bool signed = CmsSignature.Sign( dataHash, hashAlgorithmName, Certificate, PrivateKey, silent, out Oid signatureAlgorithm, out ReadOnlyMemory <byte> signatureValue); if (!signed) { throw new CryptographicException(SR.Cryptography_Cms_CannotDetermineSignatureAlgorithm); } newSignerInfo.SignatureValue = signatureValue; newSignerInfo.SignatureAlgorithm.Algorithm = signatureAlgorithm; X509Certificate2Collection certs = new X509Certificate2Collection(); certs.AddRange(Certificates); if (SignerIdentifierType != SubjectIdentifierType.NoSignature) { if (IncludeOption == X509IncludeOption.EndCertOnly) { certs.Add(Certificate); } else if (IncludeOption != X509IncludeOption.None) { X509Chain chain = new X509Chain(); chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllFlags; if (!chain.Build(Certificate)) { foreach (X509ChainStatus status in chain.ChainStatus) { if (status.Status == X509ChainStatusFlags.PartialChain) { throw new CryptographicException(SR.Cryptography_Cms_IncompleteCertChain); } } } X509ChainElementCollection elements = chain.ChainElements; int count = elements.Count; int last = count - 1; if (last == 0) { // If there's always one cert treat it as EE, not root. last = -1; } for (int i = 0; i < count; i++) { X509Certificate2 cert = elements[i].Certificate; if (i == last && IncludeOption == X509IncludeOption.ExcludeRoot && cert.SubjectName.RawData.AsSpan().SequenceEqual(cert.IssuerName.RawData)) { break; } certs.Add(cert); } } } chainCerts = certs; return(newSignerInfo); }
internal override void WriteString(AsnWriter writer, string s) => writer.WriteCharacterString(UniversalTagNumber.UTF8String, s);
internal void Encode(AsnWriter writer, Asn1Tag tag) { writer.PushSequence(tag); writer.WriteInteger(Version); try { writer.WriteObjectIdentifier(Policy); } catch (ArgumentException e) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); } MessageImprint.Encode(writer); writer.WriteInteger(SerialNumber.Span); writer.WriteGeneralizedTime(GenTime, false); if (Accuracy.HasValue) { Accuracy.Value.Encode(writer); } // DEFAULT value handler for Ordering. { AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER); tmp.WriteBoolean(Ordering); if (!tmp.EncodedValueEquals(DefaultOrdering)) { tmp.CopyTo(writer); } } if (Nonce.HasValue) { writer.WriteInteger(Nonce.Value.Span); } if (Tsa.HasValue) { writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 0)); Tsa.Value.Encode(writer); writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 0)); } if (Extensions != null) { writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 1)); for (int i = 0; i < Extensions.Length; i++) { Extensions[i].Encode(writer); } writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 1)); } writer.PopSequence(tag); }
public virtual bool TryExportRSAPublicKey(Span <byte> destination, out int bytesWritten) { AsnWriter pkcs1PublicKey = WritePkcs1PublicKey(); return(pkcs1PublicKey.TryEncode(destination, out bytesWritten)); }
private static ArraySegment <byte> EncodeAuthSafe( AsnWriter tmpWriter, ReadOnlyMemory <byte> encodedKeyContents, ReadOnlyMemory <byte> encodedCertContents, bool isPkcs12, string hmacOid, string encryptionAlgorithmOid, Span <byte> salt, Span <byte> certContentsIv) { Debug.Assert(tmpWriter.GetEncodedLength() == 0); tmpWriter.PushSequence(); if (!encodedKeyContents.IsEmpty) { tmpWriter.PushSequence(); tmpWriter.WriteObjectIdentifier(Oids.Pkcs7Data); tmpWriter.PushSequence(s_contextSpecific0); ReadOnlySpan <byte> keyContents = encodedKeyContents.Span; tmpWriter.WriteOctetString(keyContents); tmpWriter.PopSequence(s_contextSpecific0); tmpWriter.PopSequence(); } if (!encodedCertContents.IsEmpty) { tmpWriter.PushSequence(); { tmpWriter.WriteObjectIdentifier(Oids.Pkcs7Encrypted); tmpWriter.PushSequence(s_contextSpecific0); tmpWriter.PushSequence(); { // No unprotected attributes: version 0 data tmpWriter.WriteInteger(0); tmpWriter.PushSequence(); { tmpWriter.WriteObjectIdentifier(Oids.Pkcs7Data); PasswordBasedEncryption.WritePbeAlgorithmIdentifier( tmpWriter, isPkcs12, encryptionAlgorithmOid, salt, s_windowsPbe.IterationCount, hmacOid, certContentsIv); tmpWriter.WriteOctetString(encodedCertContents.Span, s_contextSpecific0); tmpWriter.PopSequence(); } tmpWriter.PopSequence(); tmpWriter.PopSequence(s_contextSpecific0); } tmpWriter.PopSequence(); } } tmpWriter.PopSequence(); int authSafeLength = tmpWriter.GetEncodedLength(); byte[] authSafe = CryptoPool.Rent(authSafeLength); if (!tmpWriter.TryEncode(authSafe, out authSafeLength)) { Debug.Fail("TryEncode failed with a pre-allocated buffer"); throw new InvalidOperationException(); } tmpWriter.Reset(); return(new ArraySegment <byte>(authSafe, 0, authSafeLength)); }
private static unsafe byte[] MacAndEncode( AsnWriter tmpWriter, ReadOnlyMemory <byte> encodedAuthSafe, ReadOnlySpan <char> passwordSpan) { Span <byte> macKey = stackalloc byte[HMACSHA1.HashSizeInBytes]; Span <byte> macSalt = stackalloc byte[HMACSHA1.HashSizeInBytes]; Span <byte> macSpan = stackalloc byte[HMACSHA1.HashSizeInBytes]; RandomNumberGenerator.Fill(macSalt); Pkcs12Kdf.DeriveMacKey( passwordSpan, HashAlgorithmName.SHA1, s_windowsPbe.IterationCount, macSalt, macKey); int bytesWritten = HMACSHA1.HashData(macKey, encodedAuthSafe.Span, macSpan); if (bytesWritten != HMACSHA1.HashSizeInBytes) { Debug.Fail($"HMACSHA1.HashData wrote {bytesWritten} of {HMACSHA1.HashSizeInBytes} bytes"); throw new CryptographicException(); } CryptographicOperations.ZeroMemory(macKey); // https://tools.ietf.org/html/rfc7292#section-4 // // PFX ::= SEQUENCE { // version INTEGER {v3(3)}(v3,...), // authSafe ContentInfo, // macData MacData OPTIONAL // } Debug.Assert(tmpWriter.GetEncodedLength() == 0); tmpWriter.PushSequence(); tmpWriter.WriteInteger(3); tmpWriter.PushSequence(); { tmpWriter.WriteObjectIdentifier(Oids.Pkcs7Data); tmpWriter.PushSequence(s_contextSpecific0); { tmpWriter.WriteOctetString(encodedAuthSafe.Span); tmpWriter.PopSequence(s_contextSpecific0); } tmpWriter.PopSequence(); } // https://tools.ietf.org/html/rfc7292#section-4 // // MacData ::= SEQUENCE { // mac DigestInfo, // macSalt OCTET STRING, // iterations INTEGER DEFAULT 1 // -- Note: The default is for historical reasons and its use is // -- deprecated. // } tmpWriter.PushSequence(); { tmpWriter.PushSequence(); { tmpWriter.PushSequence(); { tmpWriter.WriteObjectIdentifier(Oids.Sha1); tmpWriter.PopSequence(); } tmpWriter.WriteOctetString(macSpan); tmpWriter.PopSequence(); } tmpWriter.WriteOctetString(macSalt); tmpWriter.WriteInteger(s_windowsPbe.IterationCount); tmpWriter.PopSequence(); } tmpWriter.PopSequence(); return(tmpWriter.Encode()); }
private static unsafe ArraySegment <byte> EncodeAuthSafe( AsnWriter tmpWriter, SafeBagAsn[] keyBags, int keyCount, CertBagAsn[] certBags, AttributeAsn[] certAttrs, int certIdx, ReadOnlySpan <char> passwordSpan) { string?encryptionAlgorithmOid = null; bool certsIsPkcs12Encryption = false; string?certsHmacOid = null; ArraySegment <byte> encodedKeyContents = default; ArraySegment <byte> encodedCertContents = default; try { if (keyCount > 0) { encodedKeyContents = EncodeKeys(tmpWriter, keyBags, keyCount); } Span <byte> salt = stackalloc byte[16]; RandomNumberGenerator.Fill(salt); Span <byte> certContentsIv = stackalloc byte[8]; if (certIdx > 0) { encodedCertContents = EncodeCerts( tmpWriter, certBags, certAttrs, certIdx, salt, passwordSpan, certContentsIv, out certsHmacOid, out encryptionAlgorithmOid, out certsIsPkcs12Encryption); } return(EncodeAuthSafe( tmpWriter, encodedKeyContents, encodedCertContents, certsIsPkcs12Encryption, certsHmacOid !, encryptionAlgorithmOid !, salt, certContentsIv)); } finally { if (encodedCertContents.Array != null) { CryptoPool.Return(encodedCertContents); } if (encodedKeyContents.Array != null) { CryptoPool.Return(encodedKeyContents); } } }
private static ArraySegment <byte> EncodeCerts( AsnWriter tmpWriter, CertBagAsn[] certBags, AttributeAsn[] certAttrs, int certCount, Span <byte> salt, ReadOnlySpan <char> passwordSpan, Span <byte> certContentsIv, out string hmacOid, out string encryptionAlgorithmOid, out bool isPkcs12) { Debug.Assert(tmpWriter.GetEncodedLength() == 0); tmpWriter.PushSequence(); PasswordBasedEncryption.InitiateEncryption( s_windowsPbe, out SymmetricAlgorithm cipher, out hmacOid, out encryptionAlgorithmOid, out isPkcs12); using (cipher) { Debug.Assert(certContentsIv.Length * 8 == cipher.BlockSize); for (int i = certCount - 1; i >= 0; --i) { // Manually write the SafeBagAsn // https://tools.ietf.org/html/rfc7292#section-4.2 // // SafeBag ::= SEQUENCE { // bagId BAG-TYPE.&id ({PKCS12BagSet}) // bagValue [0] EXPLICIT BAG-TYPE.&Type({PKCS12BagSet}{@bagId}), // bagAttributes SET OF PKCS12Attribute OPTIONAL // } tmpWriter.PushSequence(); tmpWriter.WriteObjectIdentifierForCrypto(Oids.Pkcs12CertBag); tmpWriter.PushSequence(s_contextSpecific0); certBags[i].Encode(tmpWriter); tmpWriter.PopSequence(s_contextSpecific0); if (certAttrs[i].AttrType != null) { tmpWriter.PushSetOf(); certAttrs[i].Encode(tmpWriter); tmpWriter.PopSetOf(); } tmpWriter.PopSequence(); } tmpWriter.PopSequence(); // The padding applied will add at most a block to the output, // so ask for contentsSpan.Length + the number of bytes in a cipher block. int cipherBlockBytes = cipher.BlockSize >> 3; int requestedSize = checked (tmpWriter.GetEncodedLength() + cipherBlockBytes); byte[] certContents = CryptoPool.Rent(requestedSize); int encryptedLength = PasswordBasedEncryption.Encrypt( passwordSpan, ReadOnlySpan <byte> .Empty, cipher, isPkcs12, tmpWriter, s_windowsPbe, salt, certContents, certContentsIv); Debug.Assert(encryptedLength <= requestedSize); tmpWriter.Reset(); return(new ArraySegment <byte>(certContents, 0, encryptedLength)); } }
protected void VerifyWrite_Span_NonEncodable(string input) { AsnWriter writer = new AsnWriter(AsnEncodingRules.BER); Assert.Throws <EncoderFallbackException>(() => WriteSpan(writer, input.AsReadOnlySpan())); }
internal abstract void WriteSpan(AsnWriter writer, Asn1Tag tag, ReadOnlySpan <char> s);
internal abstract void WriteString(AsnWriter writer, Asn1Tag tag, string s);
internal void Encode(AsnWriter writer) { EncodeApplication(writer, ApplicationTag); }
private byte[] ExportPfx(SafePasswordHandle password) { int certCount = 1; if (_singleCertPal == null) { Debug.Assert(_certs != null); certCount = _certs.Count; } CertBagAsn[] certBags = ArrayPool <CertBagAsn> .Shared.Rent(certCount); SafeBagAsn[] keyBags = ArrayPool <SafeBagAsn> .Shared.Rent(certCount); AttributeAsn[] certAttrs = ArrayPool <AttributeAsn> .Shared.Rent(certCount); certAttrs.AsSpan(0, certCount).Clear(); AsnWriter tmpWriter = new AsnWriter(AsnEncodingRules.DER); ArraySegment <byte> encodedAuthSafe = default; bool gotRef = false; password.DangerousAddRef(ref gotRef); try { ReadOnlySpan <char> passwordSpan = password.DangerousGetSpan(); int keyIdx = 0; int certIdx = 0; if (_singleCertPal != null) { BuildBags( _singleCertPal, passwordSpan, tmpWriter, certBags, certAttrs, keyBags, ref certIdx, ref keyIdx); } else { foreach (X509Certificate2 cert in _certs !) { BuildBags( cert.Pal, passwordSpan, tmpWriter, certBags, certAttrs, keyBags, ref certIdx, ref keyIdx); } } encodedAuthSafe = EncodeAuthSafe( tmpWriter, keyBags, keyIdx, certBags, certAttrs, certIdx, passwordSpan); return(MacAndEncode(tmpWriter, encodedAuthSafe, passwordSpan)); } finally { password.DangerousRelease(); certAttrs.AsSpan(0, certCount).Clear(); certBags.AsSpan(0, certCount).Clear(); keyBags.AsSpan(0, certCount).Clear(); ArrayPool <AttributeAsn> .Shared.Return(certAttrs); ArrayPool <CertBagAsn> .Shared.Return(certBags); ArrayPool <SafeBagAsn> .Shared.Return(keyBags); if (encodedAuthSafe.Array != null) { CryptoPool.Return(encodedAuthSafe); } } }
public override byte[] GetSignatureAlgorithmIdentifier(HashAlgorithmName hashAlgorithm) { // If we ever support options in PSS (like MGF-2, if such an MGF is ever invented) // Or, more reasonably, supporting a custom value for the salt size. if (_padding != RSASignaturePadding.Pss) { throw new CryptographicException(SR.Cryptography_InvalidPaddingMode); } int cbSalt; string digestOid; if (hashAlgorithm == HashAlgorithmName.SHA256) { cbSalt = 256 / 8; digestOid = Oids.Sha256; } else if (hashAlgorithm == HashAlgorithmName.SHA384) { cbSalt = 384 / 8; digestOid = Oids.Sha384; } else if (hashAlgorithm == HashAlgorithmName.SHA512) { cbSalt = 512 / 8; digestOid = Oids.Sha512; } else { throw new ArgumentOutOfRangeException( nameof(hashAlgorithm), hashAlgorithm, SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithm.Name)); } // RFC 5754 says that the NULL for SHA2 (256/384/512) MUST be omitted // (https://tools.ietf.org/html/rfc5754#section-2) (and that you MUST // be able to read it even if someone wrote it down) // // Since we // * don't support SHA-1 in this class // * only support MGF-1 // * don't support the MGF PRF being different than hashAlgorithm // * use saltLength==hashLength // * don't allow custom trailer // we don't have to worry about any of the DEFAULTs. (specify, specify, specify, omit). PssParamsAsn parameters = new PssParamsAsn { HashAlgorithm = new AlgorithmIdentifierAsn { Algorithm = new Oid(digestOid) }, MaskGenAlgorithm = new AlgorithmIdentifierAsn { Algorithm = new Oid(Oids.Mgf1) }, SaltLength = cbSalt, TrailerField = 1, }; using (AsnWriter mgfParamWriter = new AsnWriter(AsnEncodingRules.DER)) { mgfParamWriter.PushSequence(); mgfParamWriter.WriteObjectIdentifier(digestOid); mgfParamWriter.PopSequence(); parameters.MaskGenAlgorithm.Parameters = mgfParamWriter.Encode(); } using (AsnWriter parametersWriter = new AsnWriter(AsnEncodingRules.DER)) using (AsnWriter identifierWriter = new AsnWriter(AsnEncodingRules.DER)) { parameters.Encode(parametersWriter); AlgorithmIdentifierAsn identifier = new AlgorithmIdentifierAsn { Algorithm = new Oid(Oids.RsaPss), Parameters = parametersWriter.Encode(), }; identifier.Encode(identifierWriter); return(identifierWriter.Encode()); } }
public static void WriteAfterDispose(bool empty) { using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER)) { if (!empty) { writer.WriteNull(); } writer.Dispose(); // Type not enum Assert.Throws <ArgumentException>( "enumType", () => writer.WriteNamedBitList(false)); // Type not enum Assert.Throws <ArgumentException>( "enumType", () => writer.WriteNamedBitList((object)"hi")); Assert.Throws <ArgumentNullException>( "enumValue", () => writer.WriteNamedBitList((object)null)); // valid input Assert.Throws <ObjectDisposedException>( () => writer.WriteNamedBitList(ReadNamedBitList.LongFlags.Mid)); // Type is not [Flags] Assert.Throws <ArgumentException>( "tEnum", () => writer.WriteNamedBitList(ReadEnumerated.UIntBacked.Fluff)); // valid input Assert.Throws <ObjectDisposedException>( () => writer.WriteNamedBitList((object)ReadNamedBitList.ULongFlags.Mid)); // Unboxed type is [Flags] Assert.Throws <ArgumentException>( "tEnum", () => writer.WriteNamedBitList((object)ReadEnumerated.SByteBacked.Fluff)); Assert.Throws <ArgumentException>( "tag", () => writer.WriteNamedBitList(Asn1Tag.Integer, false)); Assert.Throws <ArgumentException>( "tag", () => writer.WriteNamedBitList(Asn1Tag.Integer, (object)"hi")); Assert.Throws <ArgumentNullException>( "enumValue", () => writer.WriteNamedBitList(Asn1Tag.Integer, (object)null)); Assert.Throws <ArgumentException>( "tag", () => writer.WriteNamedBitList(Asn1Tag.Integer, ReadNamedBitList.LongFlags.Mid)); Assert.Throws <ArgumentException>( "tag", () => writer.WriteNamedBitList(Asn1Tag.Integer, ReadEnumerated.UIntBacked.Fluff)); Assert.Throws <ArgumentException>( "tag", () => writer.WriteNamedBitList(Asn1Tag.Integer, (object)ReadNamedBitList.ULongFlags.Mid)); Assert.Throws <ArgumentException>( "tag", () => writer.WriteNamedBitList(Asn1Tag.Integer, (object)ReadEnumerated.SByteBacked.Fluff)); Asn1Tag tag = new Asn1Tag(TagClass.Private, 6); // Type not enum Assert.Throws <ArgumentException>( "enumType", () => writer.WriteNamedBitList(tag, false)); // Type not enum Assert.Throws <ArgumentException>( "enumType", () => writer.WriteNamedBitList(tag, (object)"hi")); Assert.Throws <ArgumentNullException>( "enumValue", () => writer.WriteNamedBitList(tag, (object)null)); // valid input Assert.Throws <ObjectDisposedException>( () => writer.WriteNamedBitList(tag, ReadNamedBitList.LongFlags.Mid)); // Type is [Flags] Assert.Throws <ArgumentException>( "tEnum", () => writer.WriteNamedBitList(tag, ReadEnumerated.UIntBacked.Fluff)); // valid input Assert.Throws <ObjectDisposedException>( () => writer.WriteNamedBitList(tag, (object)ReadNamedBitList.ULongFlags.Mid)); // Unboxed type is not [Flags] Assert.Throws <ArgumentException>( "tEnum", () => writer.WriteNamedBitList(tag, (object)ReadEnumerated.SByteBacked.Fluff)); } }
public virtual byte[] ExportRSAPublicKey() { AsnWriter pkcs1PublicKey = WritePkcs1PublicKey(); return(pkcs1PublicKey.Encode()); }
/// <summary> /// To DER algorithm identifier /// </summary> /// <param name="signature"></param> /// <returns></returns> public static byte[] ToAlgorithmIdentifier(this SignatureType signature) { var hashAlgorithm = signature.ToHashAlgorithmName(); string oid; if (signature.IsRSA()) { var padding = signature.ToRSASignaturePadding(); if (padding == RSASignaturePadding.Pkcs1) { if (hashAlgorithm == HashAlgorithmName.SHA256) { oid = Oids.RsaPkcs1Sha256; } else if (hashAlgorithm == HashAlgorithmName.SHA384) { oid = Oids.RsaPkcs1Sha384; } else if (hashAlgorithm == HashAlgorithmName.SHA512) { oid = Oids.RsaPkcs1Sha512; } else { throw new ArgumentOutOfRangeException(nameof(hashAlgorithm), $"The hash algorithm {hashAlgorithm.Name} is not supported."); } using (var writer = new AsnWriter(AsnEncodingRules.DER)) { writer.PushSequence(); writer.WriteObjectIdentifier(oid); writer.WriteNull(); writer.PopSequence(); return(writer.Encode()); } } if (padding == RSASignaturePadding.Pss) { int saltLen; if (hashAlgorithm == HashAlgorithmName.SHA256) { saltLen = 256 / 8; oid = Oids.Sha256; } else if (hashAlgorithm == HashAlgorithmName.SHA384) { saltLen = 384 / 8; oid = Oids.Sha384; } else if (hashAlgorithm == HashAlgorithmName.SHA512) { saltLen = 512 / 8; oid = Oids.Sha512; } else { throw new ArgumentOutOfRangeException(nameof(hashAlgorithm), $"The hash algorithm {hashAlgorithm.Name} is not supported."); } using (var writer = new AsnWriter(AsnEncodingRules.DER)) { writer.WritePssSignatureAlgorithmIdentifier(saltLen, oid); return(writer.Encode()); } } throw new ArgumentOutOfRangeException(nameof(signature), "Specified Padding is not supported."); } if (hashAlgorithm == HashAlgorithmName.SHA256) { oid = Oids.ECDsaWithSha256; } else if (hashAlgorithm == HashAlgorithmName.SHA384) { oid = Oids.ECDsaWithSha384; } else if (hashAlgorithm == HashAlgorithmName.SHA512) { oid = Oids.ECDsaWithSha512; } else { throw new ArgumentOutOfRangeException(nameof(hashAlgorithm), $"The hash algorithm {hashAlgorithm.Name} is not supported."); } using (var writer = new AsnWriter(AsnEncodingRules.DER)) { writer.PushSequence(); writer.WriteObjectIdentifier(oid); writer.PopSequence(); return(writer.Encode()); } }
public override bool TryExportPkcs8PrivateKey(Span <byte> destination, out int bytesWritten) { AsnWriter writer = WritePkcs8PrivateKey(); return(writer.TryEncode(destination, out bytesWritten)); }
public void ComputeSignature(CmsSigner signer, bool silent) { if (signer == null) { throw new ArgumentNullException(nameof(signer)); } // While it shouldn't be possible to change the length of ContentInfo.Content // after it's built, use the property at this stage, then use the saved value // (if applicable) after this point. if (ContentInfo.Content.Length == 0) { throw new CryptographicException(SR.Cryptography_Cms_Sign_Empty_Content); } if (_hasData && signer.SignerIdentifierType == SubjectIdentifierType.NoSignature) { // Even if all signers have been removed, throw if doing a NoSignature signature // on a loaded (from file, or from first signature) document. // // This matches the NetFX behavior. throw new CryptographicException(SR.Cryptography_Cms_Sign_No_Signature_First_Signer); } if (signer.Certificate == null && signer.SignerIdentifierType != SubjectIdentifierType.NoSignature) { if (silent) { // NetFX compatibility, silent disallows prompting, so throws InvalidOperationException // in this state. // // The message is different than on NetFX, because the resource string was for // enveloped CMS recipients (and the other site which would use that resource // is unreachable code due to CmsRecipient's ctor guarding against null certificates) throw new InvalidOperationException(SR.Cryptography_Cms_NoSignerCertSilent); } // Otherwise, PNSE. .NET Core doesn't support launching the cert picker UI. throw new PlatformNotSupportedException(SR.Cryptography_Cms_NoSignerCert); } // If we had content already, use that now. // (The second signer doesn't inherit edits to signedCms.ContentInfo.Content) ReadOnlyMemory <byte> content = _heldContent ?? ContentInfo.Content; string contentType = _contentType ?? ContentInfo.ContentType.Value ?? Oids.Pkcs7Data; X509Certificate2Collection chainCerts; SignerInfoAsn newSigner = signer.Sign(content, contentType, silent, out chainCerts); bool firstSigner = false; if (!_hasData) { firstSigner = true; _signedData = new SignedDataAsn { DigestAlgorithms = Array.Empty <AlgorithmIdentifierAsn>(), SignerInfos = Array.Empty <SignerInfoAsn>(), EncapContentInfo = new EncapsulatedContentInfoAsn { ContentType = contentType }, }; // Since we're going to call Decode before this method exits we don't need to save // the copy of _heldContent or _contentType here if we're attached. if (!Detached) { using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER)) { writer.WriteOctetString(content.Span); _signedData.EncapContentInfo.Content = writer.Encode(); } } _hasData = true; } int newIdx = _signedData.SignerInfos.Length; Array.Resize(ref _signedData.SignerInfos, newIdx + 1); _signedData.SignerInfos[newIdx] = newSigner; UpdateCertificatesFromAddition(chainCerts); ConsiderDigestAddition(newSigner.DigestAlgorithm); UpdateMetadata(); if (firstSigner) { Reencode(); Debug.Assert(_heldContent != null); Debug.Assert(_contentType == contentType); } }
internal override void WriteString(AsnWriter writer, Asn1Tag tag, string s) => writer.WriteCharacterString(UniversalTagNumber.IA5String, s, tag);
public static void SerializeAllTheSimpleThings_CER() { const string ExpectedHex = "3080" + "0101FF" + "0201FE" + "020101" + "0202FEFF" + "02020101" + "0204FEFFFFFF" + "020401000001" + "0208FEFFFFFFFFFFFFFF" + "02080100000000000001" + "0209010000000000000001" + "0303000102" + "0404FF0055AA" + "0500" + "06082A8648CE3D030107" + "06072A8648CE3D0201" + "06092A864886F70D010101" + "0A011E" + "0C2544722E2026204D72732E20536D697468E280904A6F6E657320EFB9A0206368696C6472656E" + "162144722E2026204D72732E20536D6974682D4A6F6E65732026206368696C6472656E" + "1E42" + "00440072002E002000260020004D00720073002E00200053006D006900740068" + "2010004A006F006E006500730020FE600020006300680069006C006400720065" + "006E" + "3080" + "010100" + "010100" + "0101FF" + "0101FF" + "010100" + "0000" + "3180" + "020100" + "020101" + "0201FE" + "0201FF" + "02020100" + "0000" + "3080" + "020100" + "020101" + "020200FE" + "02017F" + "020200FF" + "0000" + "170D3530303130323132333435365A" + "170D3530303130323132333435365A" + // This is different than what we read in deserialize, // because we don't write back the .0004 second. "181332303136313130363031323334352E3736355A" + "180F32303136313130363031323334355A" + "020F0102030405060708090A0B0C0D0E0F" + "0000"; const string UnicodeVerifier = "Dr. & Mrs. Smith\u2010Jones \uFE60 children"; const string AsciiVerifier = "Dr. & Mrs. Smith-Jones & children"; var allTheThings = new AllTheSimpleThings { NotBool = false, SByte = -2, Byte = 1, Short = unchecked ((short)0xFEFF), UShort = 0x0101, Int = unchecked ((int)0xFEFFFFFF), UInt = 0x01000001U, Long = unchecked ((long)0xFEFFFFFFFFFFFFFF), ULong = 0x0100000000000001UL, BigIntBytes = "010000000000000001".HexToByteArray(), BitStringBytes = new byte[] { 1, 2 }, OctetStringBytes = new byte[] { 0xFF, 0, 0x55, 0xAA }, Null = new byte[] { 5, 0 }, UnattrOid = new Oid("1.2.840.10045.3.1.7", "1.2.840.10045.3.1.7"), WithName = new Oid("1.2.840.10045.2.1", "ECC"), OidString = "1.2.840.113549.1.1.1", LinearEnum = UniversalTagNumber.BMPString, Utf8Encoded = UnicodeVerifier, Ia5Encoded = AsciiVerifier, BmpEncoded = UnicodeVerifier, Bools = new[] { false, false, true, true, false }, Ints = new [] { 0, 1, -2, -1, 256 }, LittleUInts = new byte[] { 0, 1, 254, 127, 255 }, UtcTime2049 = new DateTimeOffset(1950, 1, 2, 12, 34, 56, TimeSpan.Zero), // 1950 is out of range for the reader, but the writer just does mod 100. UtcTime2099 = new DateTimeOffset(1950, 1, 2, 12, 34, 56, TimeSpan.Zero), GeneralizedTimeWithFractions = new DateTimeOffset(2016, 11, 6, 1, 23, 45, 765, TimeSpan.Zero), // The fractions will be dropped off by the serializer/writer, to simplify // the cases where the time was computed and isn't an integer number of seconds. GeneralizedTimeNoFractions = new DateTimeOffset(2016, 11, 6, 1, 23, 45, 765, TimeSpan.Zero), BigInteger = BigInteger.Parse("0102030405060708090A0B0C0D0E0F", NumberStyles.HexNumber), }; using (AsnWriter writer = AsnSerializer.Serialize(allTheThings, AsnEncodingRules.CER)) { Assert.Equal(ExpectedHex, writer.Encode().ByteArrayToHex()); } }
internal override void WriteSpan(AsnWriter writer, ReadOnlySpan <char> s) => writer.WriteCharacterString(UniversalTagNumber.UTF8String, s);
public void SealWithMac( ReadOnlySpan <char> password, HashAlgorithmName hashAlgorithm, int iterationCount) { if (iterationCount < 1) { throw new ArgumentOutOfRangeException(nameof(iterationCount)); } if (IsSealed) { throw new InvalidOperationException(SR.Cryptography_Pkcs12_PfxIsSealed); } byte[]? rentedAuthSafe = null; Span <byte> authSafeSpan = default; byte[]? rentedMac = null; Span <byte> macSpan = default; Span <byte> salt = stackalloc byte[0]; try { AsnWriter contentsWriter = new AsnWriter(AsnEncodingRules.BER); using (IncrementalHash hasher = IncrementalHash.CreateHash(hashAlgorithm)) { contentsWriter.PushSequence(); if (_contents != null) { foreach (ContentInfoAsn contentInfo in _contents) { contentInfo.Encode(contentsWriter); } } contentsWriter.PopSequence(); rentedAuthSafe = CryptoPool.Rent(contentsWriter.GetEncodedLength()); if (!contentsWriter.TryEncode(rentedAuthSafe, out int written)) { Debug.Fail("TryEncode failed with a pre-allocated buffer"); throw new InvalidOperationException(); } authSafeSpan = rentedAuthSafe.AsSpan(0, written); // Get an array of the proper size for the hash. byte[] macKey = hasher.GetHashAndReset(); rentedMac = CryptoPool.Rent(macKey.Length); macSpan = rentedMac.AsSpan(0, macKey.Length); // Since the biggest supported hash is SHA-2-512 (64 bytes), the // 128-byte cap here shouldn't ever come into play. Debug.Assert(macKey.Length <= 128); salt = stackalloc byte[Math.Min(macKey.Length, 128)]; RandomNumberGenerator.Fill(salt); Pkcs12Kdf.DeriveMacKey( password, hashAlgorithm, iterationCount, salt, macKey); using (IncrementalHash mac = IncrementalHash.CreateHMAC(hashAlgorithm, macKey)) { mac.AppendData(authSafeSpan); if (!mac.TryGetHashAndReset(macSpan, out int bytesWritten) || bytesWritten != macSpan.Length) { Debug.Fail($"TryGetHashAndReset wrote {bytesWritten} of {macSpan.Length} bytes"); throw new CryptographicException(); } } } // https://tools.ietf.org/html/rfc7292#section-4 // // PFX ::= SEQUENCE { // version INTEGER {v3(3)}(v3,...), // authSafe ContentInfo, // macData MacData OPTIONAL // } AsnWriter writer = new AsnWriter(AsnEncodingRules.BER); { writer.PushSequence(); writer.WriteInteger(3); writer.PushSequence(); { writer.WriteObjectIdentifierForCrypto(Oids.Pkcs7Data); Asn1Tag contextSpecific0 = new Asn1Tag(TagClass.ContextSpecific, 0); writer.PushSequence(contextSpecific0); { writer.WriteOctetString(authSafeSpan); writer.PopSequence(contextSpecific0); } writer.PopSequence(); } // https://tools.ietf.org/html/rfc7292#section-4 // // MacData ::= SEQUENCE { // mac DigestInfo, // macSalt OCTET STRING, // iterations INTEGER DEFAULT 1 // -- Note: The default is for historical reasons and its use is // -- deprecated. // } writer.PushSequence(); { writer.PushSequence(); { writer.PushSequence(); { writer.WriteObjectIdentifierForCrypto(PkcsHelpers.GetOidFromHashAlgorithm(hashAlgorithm)); writer.PopSequence(); } writer.WriteOctetString(macSpan); writer.PopSequence(); } writer.WriteOctetString(salt); if (iterationCount > 1) { writer.WriteInteger(iterationCount); } writer.PopSequence(); } writer.PopSequence(); _sealedData = writer.Encode(); } } finally { CryptographicOperations.ZeroMemory(macSpan); CryptographicOperations.ZeroMemory(authSafeSpan); if (rentedMac != null) { // Already cleared CryptoPool.Return(rentedMac, clearSize: 0); } if (rentedAuthSafe != null) { // Already cleared CryptoPool.Return(rentedAuthSafe, clearSize: 0); } } }
internal override void WriteSpan(AsnWriter writer, Asn1Tag tag, ReadOnlySpan <char> s) => writer.WriteCharacterString(tag, UniversalTagNumber.BMPString, s);
public void ComputeSignature(CmsSigner signer, bool silent) { if (signer == null) { throw new ArgumentNullException(nameof(signer)); } // While it shouldn't be possible to change the length of ContentInfo.Content // after it's built, use the property at this stage, then use the saved value // (if applicable) after this point. if (ContentInfo.Content.Length == 0) { throw new CryptographicException(SR.Cryptography_Cms_Sign_Empty_Content); } // If we had content already, use that now. // (The second signer doesn't inherit edits to signedCms.ContentInfo.Content) ReadOnlyMemory <byte> content = _heldContent ?? ContentInfo.Content; string contentType = _contentType ?? ContentInfo.ContentType.Value ?? Oids.Pkcs7Data; X509Certificate2Collection chainCerts; SignerInfoAsn newSigner = signer.Sign(content, contentType, silent, out chainCerts); bool firstSigner = false; if (!_hasData) { firstSigner = true; _signedData = new SignedDataAsn { DigestAlgorithms = Array.Empty <AlgorithmIdentifierAsn>(), SignerInfos = Array.Empty <SignerInfoAsn>(), EncapContentInfo = new EncapsulatedContentInfoAsn { ContentType = contentType }, }; // Since we're going to call Decode before this method exits we don't need to save // the copy of _heldContent or _contentType here if we're attached. if (!Detached) { using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER)) { writer.WriteOctetString(content.Span); _signedData.EncapContentInfo.Content = writer.Encode(); } } _hasData = true; } int newIdx = _signedData.SignerInfos.Length; Array.Resize(ref _signedData.SignerInfos, newIdx + 1); _signedData.SignerInfos[newIdx] = newSigner; UpdateCertificatesFromAddition(chainCerts); ConsiderDigestAddition(newSigner.DigestAlgorithm); UpdateMetadata(); if (firstSigner) { Reencode(); Debug.Assert(_heldContent != null); Debug.Assert(_contentType == contentType); } }
internal void Encode(AsnWriter writer) { Encode(writer, Asn1Tag.Sequence); }
private static unsafe byte[] MacAndEncode( AsnWriter tmpWriter, ReadOnlyMemory <byte> encodedAuthSafe, ReadOnlySpan <char> passwordSpan) { // Windows/macOS compatibility: Use HMAC-SHA-1, // other algorithms may not be understood byte[] macKey = new byte[20]; Span <byte> macSalt = stackalloc byte[20]; Span <byte> macSpan = stackalloc byte[20]; HashAlgorithmName hashAlgorithm = HashAlgorithmName.SHA1; RandomNumberGenerator.Fill(macSalt); fixed(byte *macKeyPtr = macKey) { Span <byte> macKeySpan = macKey; Pkcs12Kdf.DeriveMacKey( passwordSpan, hashAlgorithm, s_windowsPbe.IterationCount, macSalt, macKeySpan); using (IncrementalHash mac = IncrementalHash.CreateHMAC(hashAlgorithm, macKey)) { mac.AppendData(encodedAuthSafe.Span); if (!mac.TryGetHashAndReset(macSpan, out int bytesWritten) || bytesWritten != macSpan.Length) { Debug.Fail($"TryGetHashAndReset wrote {bytesWritten} of {macSpan.Length} bytes"); throw new CryptographicException(); } } CryptographicOperations.ZeroMemory(macKeySpan); } // https://tools.ietf.org/html/rfc7292#section-4 // // PFX ::= SEQUENCE { // version INTEGER {v3(3)}(v3,...), // authSafe ContentInfo, // macData MacData OPTIONAL // } Debug.Assert(tmpWriter.GetEncodedLength() == 0); tmpWriter.PushSequence(); tmpWriter.WriteInteger(3); tmpWriter.PushSequence(); { tmpWriter.WriteObjectIdentifier(Oids.Pkcs7Data); tmpWriter.PushSequence(s_contextSpecific0); { tmpWriter.WriteOctetString(encodedAuthSafe.Span); tmpWriter.PopSequence(s_contextSpecific0); } tmpWriter.PopSequence(); } // https://tools.ietf.org/html/rfc7292#section-4 // // MacData ::= SEQUENCE { // mac DigestInfo, // macSalt OCTET STRING, // iterations INTEGER DEFAULT 1 // -- Note: The default is for historical reasons and its use is // -- deprecated. // } tmpWriter.PushSequence(); { tmpWriter.PushSequence(); { tmpWriter.PushSequence(); { tmpWriter.WriteObjectIdentifier(Oids.Sha1); tmpWriter.PopSequence(); } tmpWriter.WriteOctetString(macSpan); tmpWriter.PopSequence(); } tmpWriter.WriteOctetString(macSalt); tmpWriter.WriteInteger(s_windowsPbe.IterationCount); tmpWriter.PopSequence(); } tmpWriter.PopSequence(); return(tmpWriter.Encode()); }