Example #1
0
        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)));
        }
Example #2
0
        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)));
        }
Example #3
0
        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()));
        }
Example #4
0
        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);
        }
Example #5
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));
        }
Example #6
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)));
        }