Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement transform: 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315' #116

Merged
merged 3 commits into from
Feb 13, 2017

Conversation

danieljoppi
Copy link
Contributor

Issues: #68 #102 #112 #113

Work for Brazilian Electronic Invoive:

const transforms = [
    'http://www.w3.org/2000/09/xmldsig#enveloped-signature',
    'http://www.w3.org/TR/2001/REC-xml-c14n-20010315'
];
const infoProvider = (pem) => {
    return {
        getKeyInfo() {
            const cert = this.getCert();
            return `<X509Data><X509Certificate>${cert}</X509Certificate></X509Data>`;
        },
        getCert() {
            const certLines = pem.certificate.split('\n');
            return certLines.filter((e, i) => i && e && e.indexOf('-----') !== 0).join('');
        }
    };
};
let signer = new SignedXml();
signer.addReference(`//*[local-name(.)=\'infNFe\']`, transforms);
signer.signingKey = new Buffer(pem.key);
signer.canonicalizationAlgorithm = 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315';
signer.keyInfoProvider = infoProvider(pem);
signer.computeSignature(canonicalXml);

console.log(signer.getSignedXml());

output (example)

<NFe>
    <infNFe Id="NFe42160512101624000184550010000014061000014065">...</infNFe>
    <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
        <SignedInfo>
            <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
            <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
            <Reference URI="#NFe42160512101624000184550010000014061000014065">
                <Transforms>
                    <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
                    <Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
                </Transforms>
                <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                <DigestValue>yuD+4VqsEzJtPHhYMD4rEKp44U=</DigestValue>
            </Reference>
        </SignedInfo>
        <SignatureValue>
            lsdjlasjdlajsdlajsdlKSAL...
        </SignatureValue>
        <KeyInfo>
            <X509Data>
                <X509Certificate>
                    KAJhkahsjkdhjasd...
                </X509Certificate>
            </X509Data>
        </KeyInfo>
    </Signature>
</NFe>

@bjrmatos
Copy link
Contributor

bjrmatos commented Sep 5, 2016

woww! that is great! @ponyesteves can you confirm if it works for you? (i haven't taken a look at the code yet)

@viniiguerrero
Copy link

viniiguerrero commented Sep 9, 2016

Hello @danieljoppi

Do you mean public or private key for these two?

signer.signingKey = new Buffer(pem.key);
signer.keyInfoProvider = infoProvider(pem);

I'm currently using a funtion to extract keys, I'd like to use with that, is that possible?

ExtrairChave : function(){ var privateKey = pki.privateKeyFromPem(fs.readFileSync(apiConfig.certificado)) var publicKey = pki.setRsaPublicKey(privateKey.n, privateKey.e) return pki.publicKeyToPem(publicKey) }

I'm getting this:

Error: error:0906D06C:PEM routines:PEM_read_bio:no start line

@danieljoppi
Copy link
Contributor Author

@viniiguerrero in my case, I use PFX cert file and I convert this file to PEM wish pemutils.

'use strict';
const $path = require('path');
const $fs = require('fs');
const pemutils = require('pemutils');

/**
 *
 * @param company
 * @returns {Promise}
 */
module.exports = (company) => {
    if (!company.pfx) {
        company.pfxFilePath = $path.resolve(company.pfxFilePath);
        company.pfx = $fs.readFileSync(company.pfxFilePath);
    }

    return new Promise(resolve => {
        pemutils.fromPfx({
            path: company.pfxFilePath,
            password: company.passw
        }, (err, pem) => {
            if (err) {
                throw err;
            }
            console.log(pem);
            resolve(pem);
        });
    });
};

output is like this:

{
    certificate: '-----BEGIN CERTIFICATE-----\nMIIIojCCBoqgAwIBAgIQWid/mQ/Zrecnz1aAFiHU7TANBgkqhkiG\n...\nGGDWU/S37s6EjMXqHmZfiAJeQaAaSahulZFn1eaIZVrgPhi4OZ/bmp\n-----END CERTIFICATE-----',
    key: '-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA1PF3Lbib8ISTK7Ic3m1tH+EWdvDouh+PSSd6omi1+XOEvauJhqIejvB0qA36\n...\nmwjEDltlfrRxan5sFFTc9NMO8A0KXLGUFPdi3OPdu53kDZGNw1qmrDfa4ngzhCqnW55hyw==\n-----END RSA PRIVATE KEY-----',
    attributes: {
        version: 2,
        subject: {
            countryName: 'BR',
            organizationName: 'ICP-Brasil',
            stateOrProvinceName: 'SC',
            localityName: 'FLORIANOPOLIS',
            organizationalUnitName: 'Japo Florianopolis',
            commonName: 'Jsppp'
        },
        issuer: {
            countryName: 'BR',
            organizationName: 'ICP-Brasil',
            organizationalUnitName: 'Secretaria da Receita Federal do Brasil - RFB',
            commonName: 'AC Instituto Fenacon RFB G2'
        },
        serial: '5A27799123FGE727CF56801621D4ED',
        notBefore: '2016-05-18T00:00:00.000Z',
        notAfter: '2017-05-17T23:59:59.000Z',
        signatureAlgorithm: 'sha256WithRSAEncryption',
        fingerPrint: '18:BA:8E:52:C1:4E:04:7F:60:18:43:EB:BB:A0:1E:77:2F:0B:F9:9B',
        publicKey: {
            algorithm: 'rsaEncryption',
            e: '65537',
            n: 'D4F1772DB89BF084932BB21C584A7AD750B1551089280B2E975FFA9'
        },
        altNames: [],
        extensions: {
            subjectAlternativeName: 'othername:<unsupported>, othername:<unsupported>, othername:<unsupported>, othername:<unsupported>, email:financeiro.propina@gmail.com',
            basicConstraints: 'CA:FALSE',
            authorityKeyIdentifier: 'keyid:EC:7A:5B:CF:86:48:83:B7:03:15:B5:C9:4D:46:D6:DC:5A:75:16:DD',
            keyUsage: 'Digital Signature, Non Repudiation, Key Encipherment',
            cRLDistributionPoints: 'Full Name:\n  URI:http://icp-brasil.acfenacon.com.br/repositorio/lcr/ACInstitutoFenaconRFBG2/LatestCRL.crl\n\nFull Name:\n  URI:http://icp-brasil.outralcr.com.br/repositorio/lcr/ACInstitutoFenaconRFBG2/LatestCRL.crl\n\nFull Name:\n  URI:http://repositorio.icpbrasil.gov.br/lcr/Certisign/ACInstitutoFenaconRFBG2/LatestCRL.crl',
            certificatePolicies: 'Policy: 2.16.76.1.2.1.34\n  CPS: http://icp-brasil.acfenacon.com.br/repositorio/dpc/AC-Instituto-Fenacon-RFB/DPC_AC_IFenacon_RFB.pdf',
            extendedKeyUsage: 'TLS Web Client Authentication, E-mail Protection',
            authorityInformationAccess: 'CA Issuers - URI:http://icp-brasil.acfenacon.com.br/repositorio/certificados/AC_Instituto_Fenacon_RFBG2.p7c\nOCSP - URI:http://ocsp.certisign.com.br'
        }
    }
}

@brilvio
Copy link

brilvio commented Feb 13, 2017

I tested here the same XML signed by ACBR on Delphi and the signatures match.

Thank you for your contribution.

@bjrmatos
Copy link
Contributor

ok, i'm going to merge this, the implementation looks solid (although i still haven't done a strict verification with the spec, because is too heavy to read that document..)

if there is some issue with the implementation, please file an issue with a failing test

@bjrmatos bjrmatos merged commit f013412 into node-saml:master Feb 13, 2017
@bjrmatos
Copy link
Contributor

@danieljoppi sorry for the long wait... if you find more improvements please open new PR's 😄

@bjrmatos
Copy link
Contributor

@danieljoppi since i'm merging #117 it seems to me that your implementation should take some code from that PR, the shape of prefixesInScope items have changed so i think it is correct to have both implementations with the same shape.

let me know your comments, when everything is ok i'll publish v0.9.0

@bonachela
Copy link

Hi @bjrmatos , do you have any idea about when v0.9.0 will be released? Waiting for the http://www.w3.org/TR/2001/REC-xml-c14n-20010315 support.
Thanks!

@bjrmatos
Copy link
Contributor

i've decided to publish a new version.. this implementation is now part of 0.9.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants