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))); }
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))); }
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))); }