public static Asn1EncodableVector GenerateSignerInfo(X509Certificate2 cert, String digestAlgorithmName, byte[] datos, AdESPolicy policy, bool signingCertificateV2, byte[] messageDigest, DateTime signDate, bool padesMode, String contentType, String contentDescription) { // ALGORITMO DE HUELLA DIGITAL AlgorithmIdentifier digestAlgorithmOID = SigUtils.MakeAlgId(AOAlgorithmID.GetOID(digestAlgorithmName)); // // ATRIBUTOS // authenticatedAttributes Asn1EncodableVector contexExpecific = InitContexExpecific( digestAlgorithmName, datos, Org.BouncyCastle.Asn1.Pkcs.PkcsObjectIdentifiers.Data.Id, messageDigest, signDate, padesMode ); // Serial Number // comentar lo de abajo para version del rfc 3852 if (signingCertificateV2) { // INICIO SINGING CERTIFICATE-V2 /** IssuerSerial ::= SEQUENCE { issuer GeneralNames, serialNumber * CertificateSerialNumber */ TbsCertificateStructure tbs = TbsCertificateStructure.GetInstance( Asn1Object.FromByteArray( new Org.BouncyCastle.X509.X509Certificate( X509CertificateStructure.GetInstance( Asn1Object.FromByteArray( cert.GetRawCertData()))).GetTbsCertificate())); GeneralNames gns = new GeneralNames(new GeneralName(tbs.Issuer)); IssuerSerial isuerSerial = new IssuerSerial(gns, tbs.SerialNumber); /** ESSCertIDv2 ::= SEQUENCE { hashAlgorithm AlgorithmIdentifier * DEFAULT {algorithm id-sha256}, certHash Hash, issuerSerial * IssuerSerial OPTIONAL } * Hash ::= OCTET STRING */ byte[] certHash = Digester.Digest(cert.GetRawCertData(), digestAlgorithmName); EssCertIDv2[] essCertIDv2 = { new EssCertIDv2(digestAlgorithmOID, certHash, isuerSerial) }; /** PolicyInformation ::= SEQUENCE { policyIdentifier CertPolicyId, * policyQualifiers SEQUENCE SIZE (1..MAX) OF PolicyQualifierInfo * OPTIONAL } * CertPolicyId ::= OBJECT IDENTIFIER * PolicyQualifierInfo ::= SEQUENCE { policyQualifierId * PolicyQualifierId, qualifier ANY DEFINED BY policyQualifierId } */ SigningCertificateV2 scv2; if (policy.GetPolicyIdentifier() != null) { /** SigningCertificateV2 ::= SEQUENCE { certs SEQUENCE OF * ESSCertIDv2, policies SEQUENCE OF PolicyInformation OPTIONAL * } */ scv2 = new SigningCertificateV2(essCertIDv2, GetPolicyInformation(policy)); // con politica } else { scv2 = new SigningCertificateV2(essCertIDv2); // Sin politica } // Secuencia con singningCertificate contexExpecific.Add(new Org.BouncyCastle.Asn1.Cms.Attribute(Org.BouncyCastle.Asn1.Pkcs.PkcsObjectIdentifiers.IdAASigningCertificateV2, new DerSet(scv2))); // FIN SINGING CERTIFICATE-V2 } else { // INICIO SINGNING CERTIFICATE /** IssuerSerial ::= SEQUENCE { issuer GeneralNames, serialNumber * CertificateSerialNumber } */ TbsCertificateStructure tbs = TbsCertificateStructure.GetInstance( Asn1Object.FromByteArray( new Org.BouncyCastle.X509.X509Certificate( X509CertificateStructure.GetInstance( Asn1Object.FromByteArray( cert.GetRawCertData()))).GetTbsCertificate())); GeneralName gn = new GeneralName(tbs.Issuer); GeneralNames gns = new GeneralNames(gn); IssuerSerial isuerSerial = new IssuerSerial(gns, tbs.SerialNumber); /** ESSCertID ::= SEQUENCE { certHash Hash, issuerSerial IssuerSerial * OPTIONAL } * Hash ::= OCTET STRING -- SHA1 hash of entire certificate */ byte[] certHash = Digester.Digest(cert.GetRawCertData(), digestAlgorithmName); EssCertID essCertID = new EssCertID(certHash, isuerSerial); /** PolicyInformation ::= SEQUENCE { policyIdentifier CertPolicyId, * policyQualifiers SEQUENCE SIZE (1..MAX) OF PolicyQualifierInfo * OPTIONAL } * CertPolicyId ::= OBJECT IDENTIFIER * PolicyQualifierInfo ::= SEQUENCE { policyQualifierId * PolicyQualifierId, qualifier ANY DEFINED BY policyQualifierId } */ SigningCertificate scv; if (policy.GetPolicyIdentifier() != null) { /** SigningCertificateV2 ::= SEQUENCE { certs SEQUENCE OF * ESSCertIDv2, policies SEQUENCE OF PolicyInformation OPTIONAL * } */ /* * HAY QUE HACER UN SEQUENCE, YA QUE EL CONSTRUCTOR DE BOUNCY * CASTLE NO TIENE DICHO CONSTRUCTOR. */ Asn1EncodableVector v = new Asn1EncodableVector(); v.Add(new DerSequence(essCertID)); v.Add(new DerSequence(GetPolicyInformation(policy))); scv = SigningCertificate.GetInstance(new DerSequence(v)); // con politica } else { scv = new SigningCertificate(essCertID); // Sin politica } /** id-aa-signingCertificate OBJECT IDENTIFIER ::= { iso(1) * member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) smime(16) * id-aa(2) 12 } */ // Secuencia con singningCertificate contexExpecific.Add(new Org.BouncyCastle.Asn1.Cms.Attribute(Org.BouncyCastle.Asn1.Pkcs.PkcsObjectIdentifiers.IdAASigningCertificate, new DerSet(scv))); } // INICIO SIGPOLICYID ATTRIBUTE if (policy.GetPolicyIdentifier() != null) { /** * SigPolicyId ::= OBJECT IDENTIFIER Politica de firma. */ DerObjectIdentifier doiSigPolicyId = new DerObjectIdentifier(policy.GetPolicyIdentifier().ToLower().Replace("urn:oid:", "")); /** * OtherHashAlgAndValue ::= SEQUENCE { * hashAlgorithm AlgorithmIdentifier, * hashValue OCTET STRING } * */ // Algoritmo para el hash AlgorithmIdentifier hashid; // si tenemos algoritmo de calculo de hash, lo ponemos if (policy.GetPolicyIdentifierHashAlgorithm() != null) { hashid = SigUtils.MakeAlgId( AOAlgorithmID.GetOID( AOSignConstants.GetDigestAlgorithmName( policy.GetPolicyIdentifierHashAlgorithm()))); } // si no tenemos, ponemos el algoritmo de firma. else { hashid = digestAlgorithmOID; } // hash del documento, descifrado en b64 byte[] hashed; if (policy.GetPolicyIdentifierHash() != null) { hashed = System.Convert.FromBase64String(policy.GetPolicyIdentifierHash()); } else { hashed = new byte[] { 0 }; } DigestInfo otherHashAlgAndValue = new DigestInfo(hashid, hashed); /** * SigPolicyQualifierInfo ::= SEQUENCE { * SigPolicyQualifierId SigPolicyQualifierId, * SigQualifier ANY DEFINED BY policyQualifierId } */ AOSigPolicyQualifierInfo spqInfo = null; if (policy.GetPolicyQualifier() != null) { spqInfo = new AOSigPolicyQualifierInfo(policy.GetPolicyQualifier().ToString()); } /** * SignaturePolicyId ::= SEQUENCE { * sigPolicyId SigPolicyId, * sigPolicyHash SigPolicyHash, * sigPolicyQualifiers SEQUENCE SIZE (1..MAX) OF * AOSigPolicyQualifierInfo OPTIONAL} * */ Asn1EncodableVector v = new Asn1EncodableVector(); // sigPolicyId v.Add(doiSigPolicyId); // sigPolicyHash v.Add(otherHashAlgAndValue.ToAsn1Object()); // como sequence // sigPolicyQualifiers if (spqInfo != null) { v.Add(spqInfo.toASN1Primitive()); } DerSequence ds = new DerSequence(v); // Secuencia con singningCertificate contexExpecific.Add(new Org.BouncyCastle.Asn1.Cms.Attribute(Org.BouncyCastle.Asn1.Pkcs.PkcsObjectIdentifiers.IdAAEtsSigPolicyID, new DerSet(ds.ToAsn1Object()))); // FIN SIGPOLICYID ATTRIBUTE } /** * Secuencia con el tipo de contenido firmado. No se agrega en firmas PAdES. * * ContentHints ::= SEQUENCE { * contentDescription UTF8String (SIZE (1..MAX)) OPTIONAL, * contentType ContentType } */ if (contentType != null && !padesMode) { ContentHints contentHints; if (contentDescription != null) { contentHints = new ContentHints(new DerObjectIdentifier(contentType), new DerUtf8String(contentDescription)); } else { contentHints = new ContentHints(new DerObjectIdentifier(contentType)); } contexExpecific.Add(new Org.BouncyCastle.Asn1.Cms.Attribute( Org.BouncyCastle.Asn1.Pkcs.PkcsObjectIdentifiers.IdAAContentHint, new DerSet(contentHints.ToAsn1Object()))); } return(contexExpecific); }
public static byte[] generateSignedData( P7ContentSignerParameters parameters, bool omitContent, AdESPolicy policy, bool signingCertificateV2, X509Certificate2 keyEntry, byte[] messageDigest, bool padesMode, String contentType, String contentDescription) { if (parameters == null) { throw new ArgumentNullException("Los parametros no pueden ser nulos"); } String signatureAlgorithm = parameters.GetSignatureAlgorithm(); X509Certificate2[] signerCertificateChain = parameters.GetSignerCertificateChain(); DateTime signDate = DateTime.Now; // Ya que el contenido de la firma puede ser grande, lo obtenemos solo al principio byte[] content = parameters.GetContent(); byte[] preSignature = CAdESTriPhaseSigner.PreSign( AOSignConstants.GetDigestAlgorithmName(signatureAlgorithm), (omitContent) ? null : content, signerCertificateChain, policy, signingCertificateV2, (messageDigest == null && content != null) ? Digester.Digest(content, AOSignConstants.GetDigestAlgorithmName(signatureAlgorithm)) : messageDigest, signDate, padesMode, contentType, contentDescription ); byte[] signature = new AOPkcs1Signer().sign(preSignature, signatureAlgorithm, keyEntry); return(CAdESTriPhaseSigner.PostSign( AOSignConstants.GetDigestAlgorithmName(signatureAlgorithm), (omitContent) ? null : content, signerCertificateChain, signature, // Volvemos a crear la prefirma simulando una firma trifasica en la que la postfirma no cuenta con el // resultado de la prefirma CAdESTriPhaseSigner.PreSign( AOSignConstants.GetDigestAlgorithmName(signatureAlgorithm), (omitContent) ? null : content, signerCertificateChain, policy, signingCertificateV2, (messageDigest == null && content != null) ? Digester.Digest(content, AOSignConstants.GetDigestAlgorithmName(signatureAlgorithm)) : messageDigest, signDate, padesMode, contentType, contentDescription ) )); }
/** Firma datos en formato CAdES.<br/> * @param data Datos que deseamos firmar. * @param algorithm Algoritmo a usar para la firma. * <p>Se aceptan los siguientes algoritmos en el parámetro <code>algorithm</code>:</p> * <ul> * <li> <i>SHA1withRSA</i></li> * <li> <i>MD5withRSA</i> (no recomendado por vulnerable)</li> * <li> <i>MD2withRSA</i> (no recomendado por vulnerable)</li> * <li> <i>SHA256withRSA</i></li> * <li> <i>SHA384withRSA</i></li> * <li> <i>SHA512withRSA</i></li> * </ul> * @param keyEntry Entrada que apunta a la clave privada a usar para firmar * @param xParams Parámetros adicionales para la firma. * <p>Se aceptan los siguientes valores en el parámetro <code>xParams</code>:</p> * <dl> * <dt><b><i>includeOnlySignningCertificate</i></b></dt> * <dd> * Si se establece a {@code true} se incluye en la firma únicamente el certificado del firmante (y no la cadena de certificación completa). * Si no se establece o se establece a o {@code false} se incluirá toda la cadena de certificación. * </dd> * <dt><b><i>mode</i></b></dt> * <dd> * Modo de firma a usar. El valor <code>explicit</code> indica que no se incluyen los datos firmados, sino una * referencia a estos, mientras que el valor <code>implicit</code> indica que sí se incluirán dentro de * la propia firma los datos firmados * </dd> * <dt><b><i>policyIdentifier</i></b></dt> * <dd> * Identificador de la política de firma. Debe ser un OID (o una URN de tipo OID) que identifique * únivocamente la política en formato ASN.1 procesable. * </dd> * <dt><b><i>policyIdentifierHash</i></b></dt> * <dd> * Huella digital del documento de política de firma (normalmente del mismo fichero en formato ASN.1 procesable). * Si no se indica una huella digital y el parámetro <code>policyIdentifier</code> no es una URL accesible * universalmente se usará <code>0</code>, mientras que si no se indica una huella digital pero el parámetro * <code>policyIdentifier</code> es una URL accesible universalmente, se descargara el fichero apuntado por la URL para calcular la huella * digital <i>al vuelo</i>. * </dd> * <dt><b><i>policyIdentifierHashAlgorithm</i></b></dt> * <dd> * Algoritmo usado para el cálculo de la huella digital indicada en el parámetro <code>policyIdentifierHash</code>. * Es obligario indicarlo cuando se proporciona una huella digital distinta de <code>0</code>. * </dd> * <dt><b><i>policyQualifier</i></b></dt> * <dd> * URL que apunta al documento descriptivo de la política de firma (normalmente un documento PDF con una descripción textual). * </dd> * <dt><b><i>precalculatedHashAlgorithm</i></b></dt> * <dd> * Algoritmo de huella digital (a usar para la firma) cuando esta se proporciona precalculada. Cuando se usan modos de firma * <i>explícitos</i>, en los que los datos no se incluyen en la firma, es posible trabajar sin proporcionarlos, indicando * únicamente su huella digital en el parámetro <code>data</code> y el algoritmo usado para su cálculo.<br> * <b> * Siempre que se de valor a este parámetro se supondrá que los datos proporcionados en el parámetro * <code>data</code> son la huella digital de los datos a firmar, y no los datos a firmar en si. * </b> * </dd> * <dt><b><i>signingCertificateV2</i></b></dt> * <dd> * Debe establecerse a <code>true</code> si se desea usar la versión 2 del atributo * <i>Signing Certificate</i> de CAdES. Si no se establece un valor para este parámetro * se utilizaráa la versión 1 con las firmas realizadas con algoritmos SHA1 y * la versión 2 con las firmas realizadas con cualquier otro algoritmo. * </dd> * </dl> * @return Firma en formato CAdES * @throws AOException Cuando ocurre cualquier problema durante el proceso */ public byte[] sign(byte[] data, String algorithm, X509Certificate2[] keyEntry, Dictionary <string, string> xParams) { //Aunque está implementado, omitimos el checkeo de BC. Razon: mirar dentro de la clase BCChecker(). //new BCChecker().checkBouncyCastle(); Dictionary <string, string> extraParams = xParams != null ? xParams : new Dictionary <string, string>(); string precalculatedDigest = null; extraParams.TryGetValue("precalculatedHashAlgorithm", out precalculatedDigest); byte[] messageDigest = null; if (precalculatedDigest != null) { messageDigest = data; } bool signingCertificateV2 = false; if (AOSignConstants.isSHA2SignatureAlgorithm(algorithm)) { signingCertificateV2 = true; } else if (extraParams.ContainsKey("signingCertificateV2")) { string signing = null; extraParams.TryGetValue("signingCertificateV2", out signing); if (signing != null) { signingCertificateV2 = Boolean.Parse(signing); } } else { signingCertificateV2 = !"SHA1".Equals(AOSignConstants.GetDigestAlgorithmName(algorithm)); } string mode = AOSignConstants.DEFAULT_SIGN_MODE; extraParams.TryGetValue("mode", out mode); //string includeOnlySignningCertificate = null; //extraParams.TryGetValue("includeOnlySignningCertificate", out includeOnlySignningCertificate); //if(includeOnlySignningCertificate!= null){ // bool include = Boolean.Parse(includeOnlySignningCertificate); // if(include){ // } //} P7ContentSignerParameters csp = new P7ContentSignerParameters( data, algorithm, keyEntry ); try { bool omitContent = false; if (mode.Equals(AOSignConstants.SIGN_MODE_EXPLICIT) || precalculatedDigest != null) { omitContent = true; } String contentTypeOid = AOSignConstants.DEFAULT_CONTENT_OID_DATA; String contentDescription = AOSignConstants.DEFAULT_CONTENT_DESCRIPTION; // DE MOMENTO NO VAMOS A CALCULAR EL MIMETYPE. MANTENDREMOS SIEMPRE POR DEFECTO LOS MISMOS //if (data != null) { // try { // MimeHelper mimeHelper = new MimeHelper(data); // contentDescription = mimeHelper.getDescription(); // contentTypeOid = MimeHelper.transformMimeTypeToOid(mimeHelper.getMimeType()); // } catch (Exception e) { // Console.WriteLine("No se han podido cargar las librerias para identificar el tipo de dato firmado: " + e); // } //} bool padesMode = false; string sPadesMode = null; extraParams.TryGetValue("padesMode", out sPadesMode); if (sPadesMode != null) { padesMode = Boolean.Parse(sPadesMode); } return(GenCAdESEPESSignedData.generateSignedData( csp, omitContent, new AdESPolicy(extraParams), signingCertificateV2, keyEntry[0], //cogemos el elemento 0, que es el que contiene el certificado raiz messageDigest, padesMode, contentTypeOid, contentDescription )); } catch (Exception e) { throw new Exception("Error generando la firma CAdES: " + e, e); } }