internal byte[][] EncodeUri(Uri uri) { byte[][] uriTlv = DerEncoder.SegmentedEncodeIA5String(uri.AbsoluteUri.ToCharArray()); uriTlv[0][0] = (byte)GeneralNameTag.Uri; return(uriTlv); }
public X509Extension Build(bool critical = false) { return(new X509Extension( Oids.SubjectAltName, DerEncoder.ConstructSequence(_encodedTlvs), critical)); }
public override byte[] GetSignatureAlgorithmIdentifier(HashAlgorithmName hashAlgorithm) { string oid; 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), hashAlgorithm, SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithm.Name)); } return(DerEncoder.ConstructSequence( DerEncoder.SegmentedEncodeOid(oid), DerEncoder.SegmentedEncodeNull())); }
internal byte[][] EncodeEmailAddress(string emailAddress) { byte[][] rfc822NameTlv = DerEncoder.SegmentedEncodeIA5String(emailAddress.ToCharArray()); rfc822NameTlv[0][0] = (byte)GeneralNameTag.Rfc822Name; return(rfc822NameTlv); }
internal byte[][] EncodeDnsName(string dnsName) { string idnaName = s_idnMapping.GetAscii(dnsName); byte[][] dnsNameTlv = DerEncoder.SegmentedEncodeIA5String(idnaName.ToCharArray()); dnsNameTlv[0][0] = (byte)GeneralNameTag.DnsName; return(dnsNameTlv); }
internal byte[][] EncodeIpAddress(IPAddress address) { byte[] addressBytes = address.GetAddressBytes(); byte[][] ipAddressTlv = DerEncoder.SegmentedEncodeOctetString(addressBytes); ipAddressTlv[0][0] = (byte)GeneralNameTag.IpAddress; return(ipAddressTlv); }
public override byte[] SignData(byte[] data, HashAlgorithmName hashAlgorithm) { byte[] ieeeFormat = _key.SignData(data, hashAlgorithm); Debug.Assert(ieeeFormat.Length % 2 == 0); int segmentLength = ieeeFormat.Length / 2; return(DerEncoder.ConstructSequence( DerEncoder.SegmentedEncodeUnsignedInteger(ieeeFormat, 0, segmentLength), DerEncoder.SegmentedEncodeUnsignedInteger(ieeeFormat, segmentLength, segmentLength))); }
internal static byte[][] SegmentedEncodeSubjectPublicKeyInfo(this PublicKey publicKey) { if (publicKey == null) { throw new ArgumentNullException(nameof(publicKey)); } if (publicKey.Oid == null || string.IsNullOrEmpty(publicKey.Oid.Value) || publicKey.EncodedKeyValue == null) { throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidPublicKey_Object)); } // SubjectPublicKeyInfo::= SEQUENCE { // algorithm AlgorithmIdentifier, // subjectPublicKey BIT STRING // } // // AlgorithmIdentifier::= SEQUENCE { // algorithm OBJECT IDENTIFIER, // parameters ANY DEFINED BY algorithm OPTIONAL // } byte[][] algorithmIdentifier; if (publicKey.EncodedParameters == null) { algorithmIdentifier = DerEncoder.ConstructSegmentedSequence( DerEncoder.SegmentedEncodeOid(publicKey.Oid)); } else { DerSequenceReader validator = DerSequenceReader.CreateForPayload(publicKey.EncodedParameters.RawData); validator.ValidateAndSkipDerValue(); if (validator.HasData) { throw new CryptographicException(SR.GetString(SR.Cryptography_Der_Invalid_Encoding)); } algorithmIdentifier = DerEncoder.ConstructSegmentedSequence( DerEncoder.SegmentedEncodeOid(publicKey.Oid), publicKey.EncodedParameters.RawData.WrapAsSegmentedForSequence()); } return(DerEncoder.ConstructSegmentedSequence( algorithmIdentifier, DerEncoder.SegmentedEncodeBitString( publicKey.EncodedKeyValue.RawData))); }
protected override PublicKey BuildPublicKey() { ECParameters ecParameters = _key.ExportParameters(false); if (!ecParameters.Curve.IsNamed) { throw new InvalidOperationException(SR.GetString(SR.Cryptography_ECC_NamedCurvesOnly)); } string curveOid = ecParameters.Curve.Oid.Value; if (string.IsNullOrEmpty(curveOid)) { string friendlyName = ecParameters.Curve.Oid.FriendlyName; // Translate the three curves that were supported Windows 7-8.1, but emit no Oid.Value; // otherwise just wash the friendly name back through Oid to see if we can get a value. switch (friendlyName) { case "nistP256": curveOid = Oids.EccCurveSecp256r1; break; case "nistP384": curveOid = Oids.EccCurveSecp384r1; break; case "nistP521": curveOid = Oids.EccCurveSecp521r1; break; default: curveOid = new Oid(friendlyName).Value; break; } } Debug.Assert(ecParameters.Q.X.Length == ecParameters.Q.Y.Length); byte[] uncompressedPoint = new byte[1 + ecParameters.Q.X.Length + ecParameters.Q.Y.Length]; // Uncompressed point (0x04) uncompressedPoint[0] = 0x04; Buffer.BlockCopy(ecParameters.Q.X, 0, uncompressedPoint, 1, ecParameters.Q.X.Length); Buffer.BlockCopy(ecParameters.Q.Y, 0, uncompressedPoint, 1 + ecParameters.Q.X.Length, ecParameters.Q.Y.Length); Oid ecPublicKey = new Oid(Oids.Ecc); return(new PublicKey( ecPublicKey, new AsnEncodedData(ecPublicKey, DerEncoder.EncodeOid(curveOid)), new AsnEncodedData(ecPublicKey, uncompressedPoint))); }
internal static byte[][] SegmentedEncodedX509Extension(this X509Extension extension) { if (extension.Critical) { return(DerEncoder.ConstructSegmentedSequence( DerEncoder.SegmentedEncodeOid(extension.Oid), DerEncoder.SegmentedEncodeBoolean(extension.Critical), DerEncoder.SegmentedEncodeOctetString(extension.RawData))); } return(DerEncoder.ConstructSegmentedSequence( DerEncoder.SegmentedEncodeOid(extension.Oid), DerEncoder.SegmentedEncodeOctetString(extension.RawData))); }
internal byte[] Sign(X509SignatureGenerator signatureGenerator, HashAlgorithmName hashAlgorithm) { if (signatureGenerator == null) { throw new ArgumentNullException(nameof(signatureGenerator)); } byte[] encoded = Encode(signatureGenerator, hashAlgorithm); byte[] signature = signatureGenerator.SignData(encoded, hashAlgorithm); return(DerEncoder.ConstructSequence( encoded.WrapAsSegmentedForSequence(), signatureGenerator.GetSignatureAlgorithmIdentifier(hashAlgorithm).WrapAsSegmentedForSequence(), DerEncoder.SegmentedEncodeBitString(signature))); }
internal static byte[][] SegmentedEncodeAttributeSet(this IEnumerable <X501Attribute> attributes) { List <byte[][]> encodedAttributes = new List <byte[][]>(); foreach (X501Attribute attribute in attributes) { encodedAttributes.Add( DerEncoder.ConstructSegmentedSequence( DerEncoder.SegmentedEncodeOid(attribute.Oid), DerEncoder.ConstructSegmentedPresortedSet( attribute.RawData.WrapAsSegmentedForSequence()))); } return(DerEncoder.ConstructSegmentedSet(encodedAttributes.ToArray())); }
internal byte[] ToPkcs10Request(X509SignatureGenerator signatureGenerator, HashAlgorithmName hashAlgorithm) { // State validation should be runtime checks if/when this becomes public API Debug.Assert(signatureGenerator != null); Debug.Assert(Subject != null); Debug.Assert(PublicKey != null); // CertificationRequest ::= SEQUENCE { // certificationRequestInfo CertificationRequestInfo, // signatureAlgorithm AlgorithmIdentifier{ { SignatureAlgorithms } }, // signature BIT STRING // } byte[] encoded = Encode(); byte[] signature = signatureGenerator.SignData(encoded, hashAlgorithm); return(DerEncoder.ConstructSequence( encoded.WrapAsSegmentedForSequence(), signatureGenerator.GetSignatureAlgorithmIdentifier(hashAlgorithm).WrapAsSegmentedForSequence(), DerEncoder.SegmentedEncodeBitString(signature))); }
protected override PublicKey BuildPublicKey() { RSAParameters parameters = _key.ExportParameters(false); byte[] rsaPublicKey = DerEncoder.ConstructSequence( DerEncoder.SegmentedEncodeUnsignedInteger(parameters.Modulus), DerEncoder.SegmentedEncodeUnsignedInteger(parameters.Exponent)); Oid oid = new Oid(Oids.RsaRsa); // The OID is being passed to everything here because that's what // X509Certificate2.PublicKey does. return(new PublicKey( oid, // Encode the DER-NULL even though it is OPTIONAL, because everyone else does. // // This is due to one version of the ASN.1 not including OPTIONAL, and that was // the version that got predominately implemented for RSA. Now it's convention. new AsnEncodedData(oid, new byte[] { 0x05, 0x00 }), new AsnEncodedData(oid, rsaPublicKey))); }
internal byte[][] EncodeUserPrincipalName(string upn) { // AnotherName ::= SEQUENCE { // type-id OBJECT IDENTIFIER, // value[0] EXPLICIT ANY DEFINED BY type-id // } byte[][] upnUtf8 = DerEncoder.SegmentedEncodeUtf8String(upn.ToCharArray()); // [0] EXPLICIT byte[][] payloadTlv = DerEncoder.ConstructSegmentedSequence(upnUtf8); payloadTlv[0][0] = DerSequenceReader.ContextSpecificConstructedTag0; byte[][] anotherNameTlv = DerEncoder.ConstructSegmentedSequence( DerEncoder.SegmentedEncodeOid(Oids.UserPrincipalName), payloadTlv); anotherNameTlv[0][0] = (byte)GeneralNameTag.OtherName; return(anotherNameTlv); }
private static byte[][] EncodeValidityField(DateTimeOffset validityField, string propertyName) { /* https://tools.ietf.org/html/rfc3280#section-4.1.2.5 * 4.1.2.5 Validity * * The certificate validity period is the time interval during which the * CA warrants that it will maintain information about the status of the * certificate. The field is represented as a SEQUENCE of two dates: * the date on which the certificate validity period begins (notBefore) * and the date on which the certificate validity period ends * (notAfter). Both notBefore and notAfter may be encoded as UTCTime or * GeneralizedTime. * * CAs conforming to this profile MUST always encode certificate * validity dates through the year 2049 as UTCTime; certificate validity * dates in 2050 or later MUST be encoded as GeneralizedTime. * * The validity period for a certificate is the period of time from * notBefore through notAfter, inclusive. */ DateTime utcValue = validityField.UtcDateTime; // On the one hand, GeneralizedTime easily goes back to 1000, and possibly to 0000; // but on the other, dates before computers are just a bit beyond the pale. if (utcValue.Year < 1950) { throw new ArgumentOutOfRangeException(propertyName, utcValue, SR.GetString(SR.Cryptography_CertReq_DateTooOld)); } // Since the date encoding is effectively a DER rule (ensuring that two encoders // produce the same result), no option exists to encode the validity field as a // GeneralizedTime when it fits in the UTCTime constraint. if (utcValue.Year < 2050) { return(DerEncoder.SegmentedEncodeUtcTime(utcValue)); } return(DerEncoder.SegmentedEncodeGeneralizedTime(utcValue)); }
private byte[] Encode() { // CertificationRequestInfo::= SEQUENCE { // version INTEGER { v1(0) } (v1,...), // subject Name, // subjectPKInfo SubjectPublicKeyInfo{ { PKInfoAlgorithms } }, // attributes[0] Attributes{ { CRIAttributes } } // } // // Attributes { ATTRIBUTE:IOSet } ::= SET OF Attribute{{ IOSet }} byte[][] attrSet = Attributes.SegmentedEncodeAttributeSet(); // Replace the tag with ContextSpecific0. attrSet[0][0] = DerSequenceReader.ContextSpecificConstructedTag0; return(DerEncoder.ConstructSequence( s_encodedVersion, Subject.RawData.WrapAsSegmentedForSequence(), PublicKey.SegmentedEncodeSubjectPublicKeyInfo(), attrSet)); }
private static byte[] EncodeAttribute(IEnumerable <X509Extension> extensions) { if (extensions == null) { throw new ArgumentNullException(nameof(extensions)); } // extensionRequest ATTRIBUTE ::= { // WITH SYNTAX ExtensionRequest // SINGLE VALUE TRUE // ID pkcs-9-at-extensionRequest // } // // ExtensionRequest ::= Extensions // // Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension // // Extension ::= SEQUENCE { // extnID OBJECT IDENTIFIER, // critical BOOLEAN DEFAULT FALSE, // extnValue OCTET STRING } List <byte[][]> encodedExtensions = new List <byte[][]>(); foreach (X509Extension extension in extensions) { if (extension == null) { continue; } encodedExtensions.Add(extension.SegmentedEncodedX509Extension()); } // The SEQUENCE over the encodedExtensions list is the value of // Extensions/ExtensionRequest. return(DerEncoder.ConstructSequence(encodedExtensions.ToArray())); }
private byte[] Encode(X509SignatureGenerator signatureGenerator, HashAlgorithmName hashAlgorithm) { // State validation should be runtime checks if/when this becomes public API Debug.Assert(Subject != null); Debug.Assert(PublicKey != null); // Under a public API model we could allow these to be null for a self-signed case. Debug.Assert(SerialNumber != null); Debug.Assert(Issuer != null); List <byte[][]> encodedFields = new List <byte[][]>(); byte version = Version; if (version != 0) { byte[][] encodedVersion = DerEncoder.ConstructSegmentedSequence( DerEncoder.SegmentedEncodeUnsignedInteger(new[] { version })); encodedVersion[0][0] = DerSequenceReader.ContextSpecificConstructedTag0; encodedFields.Add(encodedVersion); } encodedFields.Add(DerEncoder.SegmentedEncodeUnsignedInteger(SerialNumber)); // SignatureAlgorithm: Use the specified value, or ask the generator (without mutating the class) byte[] signatureAlgorithm = SignatureAlgorithm ?? signatureGenerator.GetSignatureAlgorithmIdentifier(hashAlgorithm); EncodingHelpers.ValidateSignatureAlgorithm(signatureAlgorithm); encodedFields.Add(signatureAlgorithm.WrapAsSegmentedForSequence()); // For public API allowing self-sign ease-of-use, this could be (Issuer ?? Subject). encodedFields.Add(Issuer.RawData.WrapAsSegmentedForSequence()); encodedFields.Add( DerEncoder.ConstructSegmentedSequence( EncodeValidityField(NotBefore, nameof(NotBefore)), EncodeValidityField(NotAfter, nameof(NotAfter)))); encodedFields.Add(Subject.RawData.WrapAsSegmentedForSequence()); encodedFields.Add(PublicKey.SegmentedEncodeSubjectPublicKeyInfo()); // Issuer and Subject Unique ID values would go here, if they were supported. if (Extensions.Count > 0) { Debug.Assert(version >= 2); List <byte[][]> encodedExtensions = new List <byte[][]>(Extensions.Count); // extensions[3] Extensions OPTIONAL // // Since this doesn't say IMPLICIT, it will look like // // A3 [length] // 30 [length] // First Extension // Second Extension // ... // An interesting quirk of skipping null values here is that // Extensions.Count == 0 => no extensions // Extensions.ContainsOnly(null) => empty extensions list HashSet <string> usedOids = new HashSet <string>(Extensions.Count); foreach (X509Extension extension in Extensions) { if (extension == null) { continue; } if (!usedOids.Add(extension.Oid.Value)) { throw new InvalidOperationException( SR.GetString(SR.Cryptography_CertReq_DuplicateExtension, extension.Oid.Value)); } encodedExtensions.Add(extension.SegmentedEncodedX509Extension()); } byte[][] extensionField = DerEncoder.ConstructSegmentedSequence( DerEncoder.ConstructSegmentedSequence(encodedExtensions)); extensionField[0][0] = DerSequenceReader.ContextSpecificConstructedTag3; encodedFields.Add(extensionField); } return(DerEncoder.ConstructSequence(encodedFields)); }
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); } uint 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)); } // RSASSA-PSS-params comes from RFC 4055, section 3.1: // https://tools.ietf.org/html/rfc4055#section-3.1 // // RSASSA-PSS-params ::= SEQUENCE { // hashAlgorithm [0] HashAlgorithm DEFAULT sha1Identifier, // maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT mgf1SHA1Identifier, // saltLength [2] INTEGER DEFAULT 20, // trailerField [3] INTEGER DEFAULT 1 } // // mgf1SHA1Identifier AlgorithmIdentifier ::= { id-mgf1, sha1Identifier } // sha1Identifier AlgorithmIdentifier ::= { id-sha1, NULL } // (and similar for SHA256/384/512) // // 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). byte[][] hashAlgorithmAlgId = DerEncoder.ConstructSegmentedSequence( DerEncoder.SegmentedEncodeOid(digestOid)); byte[][] hashAlgorithmField = DerEncoder.ConstructSegmentedSequence(hashAlgorithmAlgId); hashAlgorithmField[0][0] = DerSequenceReader.ContextSpecificConstructedTag0; byte[][] maskGenField = DerEncoder.ConstructSegmentedSequence( DerEncoder.ConstructSegmentedSequence( DerEncoder.SegmentedEncodeOid(Oids.Mgf1), hashAlgorithmAlgId)); maskGenField[0][0] = DerSequenceReader.ContextSpecificConstructedTag1; byte[][] saltLengthField = DerEncoder.ConstructSegmentedSequence( DerEncoder.SegmentedEncodeUnsignedInteger(cbSalt)); saltLengthField[0][0] = DerSequenceReader.ContextSpecificConstructedTag2; return(DerEncoder.ConstructSequence( DerEncoder.SegmentedEncodeOid(Oids.RsaSsaPss), // RSASSA-PSS-params DerEncoder.ConstructSegmentedSequence( hashAlgorithmField, maskGenField, saltLengthField))); }