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

            // 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 writer = AsnSerializer.Serialize(parameters, AsnEncodingRules.DER))
            {
                AlgorithmIdentifierAsn identifier = new AlgorithmIdentifierAsn
                {
                    Algorithm  = new Oid(Oids.RsaPss),
                    Parameters = writer.Encode(),
                };

                using (AsnWriter identifierWriter = AsnSerializer.Serialize(identifier, AsnEncodingRules.DER))
                {
                    return(identifierWriter.Encode());
                }
            }
        }
Ejemplo n.º 2
0
        private static bool VerifyX509Signature(
            ReadOnlySpan <byte> toBeSigned,
            ReadOnlySpan <byte> signature,
            PublicKey publicKey,
            AlgorithmIdentifierAsn algorithmIdentifier)
        {
            RSA?  rsa   = publicKey.GetRSAPublicKey();
            ECDsa?ecdsa = publicKey.GetECDsaPublicKey();

            try
            {
                HashAlgorithmName hashAlg;

                if (algorithmIdentifier.Algorithm == Oids.RsaPss)
                {
                    if (rsa is null || !algorithmIdentifier.Parameters.HasValue)
                    {
                        return(false);
                    }

                    PssParamsAsn pssParams = PssParamsAsn.Decode(
                        algorithmIdentifier.Parameters.GetValueOrDefault(),
                        AsnEncodingRules.DER);

                    RSASignaturePadding padding = pssParams.GetSignaturePadding();
                    hashAlg = HashAlgorithmName.FromOid(pssParams.HashAlgorithm.Algorithm);

                    return(rsa.VerifyData(
                               toBeSigned,
                               signature,
                               hashAlg,
                               padding));
                }

                switch (algorithmIdentifier.Algorithm)
                {
                case Oids.RsaPkcs1Sha256:
                case Oids.ECDsaWithSha256:
                    hashAlg = HashAlgorithmName.SHA256;
                    break;

                case Oids.RsaPkcs1Sha384:
                case Oids.ECDsaWithSha384:
                    hashAlg = HashAlgorithmName.SHA384;
                    break;

                case Oids.RsaPkcs1Sha512:
                case Oids.ECDsaWithSha512:
                    hashAlg = HashAlgorithmName.SHA512;
                    break;

                case Oids.RsaPkcs1Sha1:
                case Oids.ECDsaWithSha1:
                    hashAlg = HashAlgorithmName.SHA1;
                    break;

                default:
                    throw new NotSupportedException(
                              SR.Format(SR.Cryptography_UnknownKeyAlgorithm, algorithmIdentifier.Algorithm));
                }

                // All remaining supported algorithms have no defined parameters
                if (!algorithmIdentifier.HasNullEquivalentParameters())
                {
                    return(false);
                }

                switch (algorithmIdentifier.Algorithm)
                {
                case Oids.RsaPkcs1Sha256:
                case Oids.RsaPkcs1Sha384:
                case Oids.RsaPkcs1Sha512:
                case Oids.RsaPkcs1Sha1:
                    if (rsa is null)
                    {
                        return(false);
                    }

                    return(rsa.VerifyData(toBeSigned, signature, hashAlg, RSASignaturePadding.Pkcs1));

                case Oids.ECDsaWithSha256:
                case Oids.ECDsaWithSha384:
                case Oids.ECDsaWithSha512:
                case Oids.ECDsaWithSha1:
                    if (ecdsa is null)
                    {
                        return(false);
                    }

                    return(ecdsa.VerifyData(toBeSigned, signature, hashAlg, DSASignatureFormat.Rfc3279DerSequence));

                default:
                    Debug.Fail(
                        $"Algorithm ID {algorithmIdentifier.Algorithm} was in the first switch, but not the second");
                    return(false);
                }
            }
            catch (AsnContentException)
            {
                return(false);
            }
            catch (CryptographicException)
            {
                return(false);
            }
            finally
            {
                rsa?.Dispose();
                ecdsa?.Dispose();
            }
        }