Scam messages have been sent out in the Tax Administration’s name. Read more about scams.

Example of renewing a certificate and generating a signature (csr)

These instructions describe one way to renew a certificate issued by the Finnish Tax Administration’s certificate service and generating a signature using the Web Service API of the PKI system of the Finnish Tax Administration’s certificate service. Based on the example, you can generate the renewal of a certificate in your software.

These instructions describe the renewal of a testing certificate. These instructions also apply to the renewal of a production certificate. In this case, actual customer data and the certificate service’s production address must be used. Production customer data cannot be used in the testing environment. 

Renewing a certificate using the certificate service web service interface

  1. Requirements:

    • PKI expertise to generate a key pair and a signing request
    • Programming skills, compiling and executing the signing program
    • The certificate service’s message structures, WSDL package: https://vero.fi/globalassets/tietoa-verohallinnosta/ohjelmistokehittajille/varmennepalvelu/varmennepalvelu-rajapinta_v1.01.zip
    • A new key pair for the certificate signing request (CSR)
    • The current certificate and the private key linked to it for signing the XML message
    • The artificial Business ID and the artificial company name for the Web Service certificate used by your organisation
    • Any PFX file which contains the private key linked to the current certificate
    • The password of the current PFX file

     

  2. Required tools:

     

  3. Further information:

     

Source code of the example program (SignXmlNew)

Source code of the Finnish Tax Administration's example program (SignXmlNew) for signing an XML message for the certificate renewal interface.

using System;
using System.IO;
using System.Security.Cryptography;
using System.Security.Cryptography.Xml;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Xml;

namespace SignXmlNew
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                // Check command line parameters and, if necessary, throw an exception with usage instructions
                if (args.Length != 3 ) throw new ArgumentException("Usage: xmlFile certPfxFile certPassword");

                string xmlFile = args[0];
                var certPfxFile = args[1];
                var password = args[2];


                XmlDocument doc = new XmlDocument();
                doc.PreserveWhitespace = true;
                doc.Load(xmlFile);

                X509Certificate2 cert = new X509Certificate2(certPfxFile, password);

                SignDocumentRsaSha256(doc, cert);

                // Write the destination file that includes the Signature element
                string destination = Path.GetFileNameWithoutExtension(xmlFile) + "_signed" + Path.GetExtension(xmlFile);
                doc.Save(destination);
                Console.WriteLine("OK, created: " + destination);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error: " + ex);
                return;
            }
        }

        ///
        /// Signs the given XmlDocument using RSA-SHA256 and the provided X509 certificate.
        /// 
        ///The XmlDocument to be signed.
        ///The X509Certificate2, containing the private key for signing.
        private static void SignDocumentRsaSha256(XmlDocument xmlDoc, X509Certificate2 cert)
        {
            var rsaKey = cert.GetRSAPrivateKey();
            SignedXml signedXml = new SignedXml(xmlDoc);
            signedXml.SignedInfo.CanonicalizationMethod = "http://www.w3.org/2001/10/xml-exc-c14n#";
            signedXml.SigningKey = rsaKey;
            Reference reference = new Reference();
            reference.Uri = "";
            XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform();
            reference.AddTransform(env);
            signedXml.AddReference(reference);
            var keyInfo = new KeyInfo();
            keyInfo.AddClause(new KeyInfoX509Data(cert));
            signedXml.KeyInfo = keyInfo;
            signedXml.ComputeSignature();
            XmlElement xmlDigitalSignature = signedXml.GetXml();
            xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true));
        }
    }
}

Renewing a testing certificate

  • 1

    Generate a new private key for a new certificate

  • Generate the private key in OpenSSL using the following command:
    openssl genrsa -out newprivate.key 3072

    The certificate service supports three different key sizes (RSA key): 2048, 3072 and 4096 bits. The Tax Administration recommends using a key of at least 3072 bits to create certificates. At the end of the Open SSL command above, replace the text with 2048, 3072 or 4096, depending on the size of the key and certificate you want to generate.

    The new private key will be generated in the file newprivate.key.

  • 2

    Generate a new certificate signing request for renewal

  • Generate the certificate signing request (CSR) using the private key generated in step 1 in OpenSSL using the following command:
    openssl req -new -key newprivate.key -out certificaterequest.csr

    Enter the following information in OpenSSL in accordance with the details of the certificate to be renewed:
    Country Name = FI
    Organization Name = The name of your testing company
    Common Name = Your artificial Business ID

    The new certificate signing request will be generated in the file certificaterequest.csr.

  • 3

    Generate an XML message for signing

  • Generate the content of the XML message for renewing a certificate for the renewal API. Only this part of the message is signed. Use the attached template. Note that editors may add line breaks. It is recommended that any line breaks be removed from the template before generating the signature:

    <cer:RenewCertificateRequest xmlns:cer="http://certificates.vero.fi/2017/10/certificateservices" xmlns:xd="http://www.w3.org/2000/09/xmldsig#">
    <Environment>TEST</Environment>
    <CustomerId>Your artificial Business ID</CustomerId>
    <CustomerName>Name of the testing company</CustomerName>
    <CertificateRequest>The certificate signing request generated in step 2, i.e. the base64 character string contained by the CSR file without --- begin certificate request --- and --- end certificate request ---</CertificateRequest>
    </cer:RenewCertificateRequest>

    Enter your testing certificate’s Business ID (artificial identifier), the artificial company name and the new certificate signing request generated in step 2 (base64 character string without --- begin certificate request --- and --- end certificate request ---) in the fields of the example message. Save the XML file on a disk without any line breaks for signing.

  • 4

    Sign the XML message

  • Generate a signature for the message’s content, i.e. the part generated in step 3. You can use readily available solutions (e.g. XML Signer), build your own solution or use the Finnish Tax Administration’s example solution. These instructions are based on the Finnish Tax Administration’s C# solution. The example solution assumes that the current certificate is in the PFX file.

    Retrieve the source code of the example from the section 'Source code of the example program (SignXmlNew)'

    To run the program, download .net libraries and a suitable development environment, e.g. Visual Studio Code: https://code.visualstudio.com/ 

  • 5

    Generate a PFX file for the signing program using OpenSSL

  • Run the command below to generate a PFX file. The current certificate and the private key with which it was generated are added to the file.

    If no PFX file exists, generate it using the following command, in which case the private key and current certificate are added to it (saved in the cert.cer file in base64 format):
    openssl.exe pkcs12 -export -out new.pfx -inkey private.key -in cert.cer

    The private key of the currently used certificate is unencrypted in base64 format in the command input in the private.key file, and the certificate’s public part (i.e. the signed public key) is in base64 format in the cert.cer file.

    OpenSSL asks you to enter a password to encrypt the PFX file. The password is required in the signing program. A new new.pfx file will be generated.

    If you are testing in the test bench:
    Generate the PFX file using the command above, in which case the private key, the test bench’s SignNewCertificate_Private.key file and the current certificate retrieved from the test bench and saved in the cert.cer file in base64 format are added to it.

  • 6

    Run the signing program

  • Compile and run the signing program (SignXmlNew.exe) and enter the XML message to be signed and generated in step 3, the PFX file and the password created for it as command row parameters:
    SignXmlNew.exe renew.xml new.pfx password

  • The signed XML file renew_signed.xml will be generated; see the test bench example below:

    <cer:RenewCertificateRequest xmlns:cer="http://certificates.vero.fi/2017/10/certificateservices" xmlns:xd="http://www.w3.org/2000/09/xmldsig#">
    <Environment>TEST</Environment>
    <CustomerId>0123456-7</CustomerId>
    <CustomerName>Ab PKI Developer Company Oy</CustomerName>

    <CertificateRequest>
    MIICjTCCAXUCAQAwSDELMAkGA1UEBhMCRkkxEzARBgNVBAgMClNvbWUtU3RhdGUx
    JDAiBgNVBAoMG0FiIFBLSSBEZXZlbG9wZXIgQ29tcGFueSBPeTCCASIwDQYJKoZI
    hvcNAQEBBQADggEPADCCAQoCggEBAJkBP88eLdbxbJfPluDI/rNP0EUpluRohxgx
    MNfuYVV9kXgrMsOZpCsV/QjwZFpWBSFy6PDJIKyvAqe83XSfoGPt9apy3QaUJuXR
    4/P5H6VT+eZpt1TCf5CEaKb0aW4bZ1kN9BLerrJ81HsR6cutpE/t0bzArc4kna/l
    rz/yB3tlU34YoHyx9bXNwKSPsUdL7N32vIuSO8Me/3NjFzA9CBYRrP58qnXIyTmm
    0x5GJXGBJqJM2xBRCmpMWg5WGUOF8mAGxkPDxyEfZpaHXbSLaBQ1nJyDPg0+n/Ak
    rcweydE0BKmMh3rSITH/M5DYZ6yKgHABEWERg1Nz06ei+a+KJUcCAwEAAaAAMA0G
    CSqGSIb3DQEBCwUAA4IBAQBsIqCulgyrfU+DVZxS60Hvu4d8GcKKRGCtFBt508BM
    c+NSnevgakWZXXMWKOJStsDHsOPnwfaIvlmFLWRkAsqxt2dIGgWMzFh9NaX0Anwm
    CbiUruot9C8zguP7Y/67AFSeageNYrHmgIBHoZyNIe+tPR4Y5DxcQBl/6HtyzJ/q
    Nej5mp2zSlW5P1QoEkS3MU8Gm0mpCBylyAvCzeYHOop6caZMQctVCmPto+0PYx0T
    qEmO15vGj/rIN4btjEKSYfjNj56MMN8lsIc/6vqdikKKmMwTLRXjq73liOYyJ11s
    9433VK1J/UMvay3y2jYKVDUUw567HD8C3lsT+A+ifkCo
    </CertificateRequest>
    <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
    <SignedInfo>
    <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
    <SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
    <Reference URI="">
    <Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
    </Transforms>
    <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
    <DigestValue>i13a6CV9yr+uqy/qx4yhvyysDvcKnoiNIjUdj7Arr1A=
    </DigestValue>
    </Reference>
    </SignedInfo>
    <SignatureValue>
    VEja46Y17IaMXHMJfcZMRM+3zPTLSepv/zWeR2JLMMCz3nWl
    dJynhs1MjGMbqJ3gLsebomkE3UX10ToZ0LObtbeACFYz78dDKbWHTc4cU1IWkZU3
    DpXQ5svgJWNk1L+B2SDH7V+ethFNqBmwLCgsE2dT8pt7rXwsBOnZe/Rt30flEMd5
    sSWYYJeb1FzMXAcafVIoVs31T9HcoCFupgMH9YWsgzpknQHTSTKfjBZbhsjBnvnD
    IwSceFhxxNpcmY/zVjRVB56WeC2qhQgZFN7PsnCJ6KnNOTkYr2w7CVCFNwofCMU3
    eXUl+n5khTJmNQV+SZ2S0qPzBSp6TD/reCVJHA==
    </SignatureValue>
    <KeyInfo>
    <X509Data>
    <X509Certificate>
    MIIFqzCCA5OgAwIBAgIIGZoeTGyXo3IwDQYJKoZIhvcNAQELBQAwSjEkMCIGA1UE
    AwwbUEtJIFNlcnZpY2UgRGV2ZWxvcGVyIENBIHYxMRUwEwYDVQQKDAxWZXJvaGFs
    bGludG8xCzAJBgNVBAYTAkZJMB4XDTIwMDcwNjA4MzYzMloXDTMwMDcwNDA4MzYz
    MlowcjESMBAGA1UEAwwJMDEyMzQ1Ni03MSkwJwYDVQQFEyBDNDY4MTkxMDdCNDAx
    NUI0MUIzMTA0MTExMUE0REE2RDEkMCIGA1UECgwbQWIgUEtJIERldmVsb3BlciBD
    b21wYW55IE95MQswCQYDVQQGEwJGSTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
    AQoCggEBAMrf+WUx2nuYBOeG3PxqzIeMmMVRwlqmBTH/jdW0AmRZ34cuh+Do/T6U
    0mqg9G4lVsj8WaM8fmh7tdCQ3xcCPnqpQrkeGuWQV4nIhok74kDnQb12FrOKCsLI
    OMONHS2+9E8HKwS8giFXzKP8UUnJK8PmptJQo+E6jlEy+vzSsHouf0UMCgp9MutN
    9RlAtjqS6lyHtqp8BLn2hdEM1srIqCXBRigkAH5w1mqbBSiVkgsCaYJ+I5AY201Z
    TUlb138SY/bYk9gfLS1aY1gEF+667Bmys0aJk4JRLHujMqfkEuHrfRWo1ps739H+
    8UPqkRmJfNybGFUPoJEwcfGIkXdYGPUCAwEAAaOCAWswggFnMAwGA1UdEwEB/wQC
    MAAwHwYDVR0jBBgwFoAUT1PJe8BCr9h+uQE8W6CNC7/QfeYwUwYIKwYBBQUHAQEE
    RzBFMEMGCCsGAQUFBzAChjdodHRwOi8vY3JsLXRlc3RpLnZlcm8uZmkvY2EvUEtJ
    U2VydmljZURldmVsb3BlckNBdjEuY3J0MBMGA1UdJQQMMAoGCCsGAQUFBwMCMIGc
    BgNVHR8EgZQwgZEwgY6gPKA6hjhodHRwOi8vY3JsLXRlc3RpLnZlcm8uZmkvY3Js
    L1BLSVNlcnZpY2VEZXZlbG9wZXJDQXYxLmNybKJOpEwwSjEkMCIGA1UEAwwbUEtJ
    IFNlcnZpY2UgRGV2ZWxvcGVyIENBIHYxMRUwEwYDVQQKDAxWZXJvaGFsbGludG8x
    CzAJBgNVBAYTAkZJMB0GA1UdDgQWBBQwtQwXI5AZJVyZf4DEemCYLnw+mzAOBgNV
    HQ8BAf8EBAMCBaAwDQYJKoZIhvcNAQELBQADggIBADZkkj4T+rVlAe9a53/9zrWL
    uJqe+WePxIoEk5ozXWDb2FeR0uEyUS2Ba0gVJwPm9Go6CAia3J9nFGyVUUNCm2of
    dDGxEX4JkrRc7cO8JPaMY74tJR9wwj8R5sshAXPDVMWh9Ml8LHG6hqz0ic0lK9cS
    sAHBGJ3GBlckS/6y+SPWGKMHOf0QIm5of63qQ8aI950y4aUjL7td2Yxiu6jKUfP4
    haL0BvJFM///o6Ge5LxT3nfPZxESBLbLE21D0ksyO+fZIjIeflxIeQk9rWY7zYq/
    Go9+EIvElLXE2aDjqQrwoNIQHmqLgG0DuKpJKzSi7nRvDVHaB5YIdtLDJ4PXZlTk
    ib8QBOZWmHCw58IvfEdL0WfuRpzJmlCf8oyzLWRagtnEQhwnWnkXOtPqivRq3Rh3
    5M4mQPNVPikduzYlhvQzwCAVkzgspEZVT5hQlTEXBiZZQ8jC8Mb6U1u7G/NndHGw
    dWn0WtNYDMrhqEZGoHxgLTLwaU4d5suHzkv0gIxkreR4fnVdiVWd4zCNQk6rt9Jo
    3p0yLFGM49G3kszHPcYxxBmzqSrSBoBKX5Sn9+jOF39fxE6LNCmJBiZz49WhSOTS
    LjX/kL8B0T4NBCtz6EdhQk0lz1JC5GvNuVVnmKeZYElt3qLvx4ktc6QxlH2zZ48B
    R+m/cXycvyLzy2fgyAlW
    </X509Certificate>
    </X509Data>
    </KeyInfo>
    </Signature>
    </cer:RenewCertificateRequest>

    Note that the signing program adds the Signature block to the end of the RenewCertificateRequest block.

    It is important that the content of the file is not changed in any way before it is sent to the PKI system’s API so that the signed content remains unchanged. Changes are also caused by line breaks and other formatting, due to which the signature is no longer valid and the certificate service returns the error code PKI010.

  • 7

    Send the signed message to the certificate service’s PKI system API

  • Send the signed message for renewing a testing certificate using SoapUI, for example, to the testing address of the certificate service’s PKI system:
    https://pkiws-testi.vero.fi/2017/10/CertificateServices 

    You can download message structure templates based on the WSDL description in SoapUI. Download WSDL interface package for the certificate service:  https://vero.fi/globalassets/tietoa-verohallinnosta/ohjelmistokehittajille/varmennepalvelu/varmennepalvelu-rajapinta_v1.01.zip. Open the WSDL file using SoapUI.

    Generate the outgoing message so that the signed content remains unchanged in the body element of soap-envelope. Do not add any formatting to the signed content.

    Example of soap-envelope and the part in which the content is entered:
    <env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xs="http://www.w3.org/2001/XMLSchema" ><env:Body>
    the signed content as generated in step 4
    </env:Body></env:Envelope>

    Check the URL and send the message. ‘OK’ and ‘retrievalID’, with which the renewed certificate can be retrieved using the GetCertificate operation, will be sent as the response.

    Curl can be used instead of SoapUI, in which case you need to ensure in the Windows environment that there are no line breaks in the signed content and that all content is on a single row. Remember to add soap-envelope to the signed file. A renewal request can be sent with the Curl command below:
    curl -i -v -d @template_signed_env.xml --header "SOAPAction:renewCertificate" -H "Content-Type: text/xml;charset=UTF-8" -H "Accept-Encoding: gzip,deflate https://pkiws-testi.vero.fi/2017/10/CertificateServices 

  • 8

    Retrieve the renewed certificate using the GetCertificate operation

  • Use the certificate service’s instructions when retrieving.

  • Store the PFX file and private key with care.



Page last updated 5/21/2025