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)));
        }
Exemplo n.º 2
0
        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)));
        }
Exemplo n.º 3
0
        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));
        }
Exemplo n.º 4
0
        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)));
        }