Sample code for OpenSSL hash signing

SAS supports the following types of OpenSSL hash signing services:

  • RSAUtl
    • Takes an input file and signs it.
    • This service does not perform hashing and encoding for your file. Use this service only when your input file is an encoded hash.
  • DGST
    • Takes an input file, calculates the hash out of it, then encodes the hash and signs the hash.
    • The service does not discriminate between different file types and any input file is hashed and signed as is.
    • For example, if your input is a zip file, the service does not extract the contents inside the zip file and signs it as is.

Table:

Signing Type

Input Type

Output Type

Algorithm Type

Supported file size

RSAUtl

File Hash in base64 encoded form

Signature in base64 encoded form

Not applicable

Small only

DGST

File in base64 encoded form

signature in base64 encoded form

Note: DGST applies an extra layer of encoding.

SHA1 and SHA256

Note: SHA 256 is the default value.

Small and large

To help you get your OpenSSL hash signing up and running, we have included a sample code in this topic. This code only provides the common signing functionality. You can expand on this code sample to include other functions. We have included this code only as an example to help you understand how to use OpenSSL with SAS.

How to select the type of OpenSSL hash signing

The sample code includes two separate functions for each type of signing in commented form. While preparing your code, uncomment the appropriate function according to your requirements.

Table:

Type

Syntax

RSAUtl

base64encodedHash = calculateHash(file);

DGST

base64encodedHash = getBase64EncodedString(file);

How does the sample code work?

The sample code is a Java application that does the following tasks:

  1. Takes an input file and other input parameters.
  2. Creates a requestSigning SOAP API request and sends it to SAS.
  3. Displays the API response, which contains details like, signing set Id, signing set status, the signed hash, and the certificate chain.

Parameters

Name

Type

Description

filePath

String

Specifies the path to the file that requires signing.

file

File

The file that requires signing.

base64encodedHash

String

The hash that is calculated from the input file.

userName

String

The user name for your API account.

password

String

The password to your API account.

partnerCode

String

The partner code for API account.

publisherID

String

Your Publisher ID.

signingServiceName

String

The name of the singing service that you want to sign with.

applicationName

String

The name of the application that you want to sign.

applicationVersion

String

Optional. The version of the application.

url

String

Web service URL.

hashAlgorithm

String

Applies only to DGST signing. Specifies the type of algorithm to be used for encoding the Hash. Valid options are SHA1 and SHA256

serverURI

String

Web service URI.

Response

Name

Type

Description

signingSetID

String

The signing set ID generated by SAS.

signingSetStatus

String

See Signing set status codes.

signature

String

The signature on the file, if signing is successful.

certificate

String

The certificate used for signing.

Sample code

java
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.soap.*;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import java.io.*;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

public class SoapClient {

    /**
     * Starting point for the SOAP Client Testing
     */
    public static void main(String args[]) {
        try {

            if(args.length < 1){
                System.out.printf("Invalid Number of Arguments. Please specify the full path of the file whose hash needs to be signed");
                return;

            }


            String filePath = args[0];
            File  file = new File(filePath);
			String base64encodedHash = "";
			
			//uncomment this line to use OpenSSL with rsaUtl
            base64encodedHash = calculateHash(file);
			
			//uncomment this line to use OpenSSL with DGST
			base64encodedHash = getBase64EncodedString(file);

            /**
             * The following variable are to be set to their correct values.
             */
            String userName= "";
            String password = "";
            String partnerCode="";
            String publisherId="";
            String signingServiceName="";
            // Create SOAP Connection
            SOAPConnectionFactory soapConnectionFactory = SOAPConnectionFactory.newInstance();
            SOAPConnection soapConnection = soapConnectionFactory.createConnection();

            // Send SOAP Message to SOAP Server
            String url = "https://dev-api.geotrust.com:443/webtrust/SigningService";   //Webservice EndPoint

            SOAPMessage soapResponse = soapConnection.call(createSOAPRequest(base64encodedHash,userName,password,partnerCode,publisherId,signingServiceName), url);

            // Process the SOAP Response
            printSOAPResponse(soapResponse);

            soapConnection.close();
        } catch (Exception e) {
            System.err.println("Error occurred while sending SOAP Request to Server");
            e.printStackTrace();
        }
    }


    private static String calculateHash(File fileToHash) throws NoSuchAlgorithmException, IOException {
        String hashAlgorithm = "SHA-256"; // or "SHA-1"
        MessageDigest md = MessageDigest.getInstance(hashAlgorithm);

        InputStream is = new FileInputStream(fileToHash);
        //Create byte array to read data in chunks
            byte[] byteArray = new byte[1024];
            int bytesCount = 0;

            //Read file data and update in message digest
            while ((bytesCount = is.read(byteArray)) != -1) {
                md.update(byteArray, 0, bytesCount);
            };

            //close the stream; We don't need it now.
            is.close();

        byte[] digest = md.digest();
        byte[] bytesEncoded = Base64.getEncoder().encode(digest);
        System.out.println("Base64Encoded String: " + new String(bytesEncoded));
        return new String(bytesEncoded );


    }
	
	private static String getBase64EncodedString(File file) throws IOException{
    	   	
    	byte[] bytes= FileUtils.readFileToByteArray(file);
    	byte[] bytesEncoded = Base64.getEncoder().encode(bytes);
        System.out.println("Base64Encoded String: " + new String(bytesEncoded));
        return new String(bytesEncoded );

    }

    /**
     * Method to create the Soap Request
     * @param base64EncodedHash  - the base64 encoded hash of the file
     * @return
     * @throws Exception
     */
    private static SOAPMessage createSOAPRequest(String base64EncodedHash, String userName, String password,
                                                 String partnerCode, String publisherId, String signingServiceName) throws Exception {
        MessageFactory messageFactory = MessageFactory.newInstance();
        SOAPMessage soapMessage = messageFactory.createMessage();
        SOAPPart soapPart = soapMessage.getSOAPPart();

        String serverURI = "http://api.ws.symantec.com/webtrust/codesigningservice";

        // SOAP Envelope
        SOAPEnvelope envelope = soapPart.getEnvelope();
        envelope.addNamespaceDeclaration("example", serverURI);

        /*
        Constructed SOAP Request Message:  This is how the XML Form of SOAP Request looks like

        <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:cod="http://api.ws.symantec.com/webtrust/codesigningservice">
           <soapenv:Body>
              <cod:requestSigning>
                 <cod:requestSigningRequest>
                   <cod:authToken>
                   <cod:userName>****</cod:userName>
                   <cod:password>****</cod:password>
                   <cod:partnerCode>****</cod:partnerCode>
                 </cod:authToken>
                 <cod:publisherID>****</cod:publisherID>
                    <cod:applicationName>hash_signing</cod:applicationName>
                    <cod:applicationVersion></cod:applicationVersion>
                    <cod:signingServiceName>Hash Signing</cod:signingServiceName>
                    <cod:application>hZcdswf4ro1qmhIkdczzmFNJCwg=</cod:application>
                    <cod:commaDelimitedFileNames/>
                    <cod:signingCertificateOptions>
                       <!--You may enter the following 2 items in any order-->
                     <cod:signingAction>GENERATE_NEW_CERT</cod:signingAction>
                     <cod:certificateFriendlyName>alok31112</cod:certificateFriendlyName>
                    </cod:signingCertificateOptions>
                 </cod:requestSigningRequest>
              </cod:requestSigning>
           </soapenv:Body>
        </soapenv:Envelope>
         */

        // Creating the XML Equivalent in Java
        SOAPBody soapBody = envelope.getBody();
        SOAPElement requestSigningElement = soapBody.addChildElement("requestSigning", "example");
        SOAPElement requestSigningRequestElement = requestSigningElement.addChildElement("requestSigningRequest", "example");
        SOAPElement authTokenElement = requestSigningRequestElement.addChildElement("authToken", "example");


        //Specify the configured userName
        SOAPElement userNameElement = authTokenElement.addChildElement("userName", "example");
        userNameElement.addTextNode(userName);

        //Specify the configured password
        SOAPElement passwordElement = authTokenElement.addChildElement("password", "example");
        passwordElement.addTextNode(password);

        //Specify the partnerCode
        SOAPElement partnerCodeElement = authTokenElement.addChildElement("partnerCode", "example");
        partnerCodeElement.addTextNode(partnerCode);

        //Specify the publisherId
        SOAPElement publisherIdElement = requestSigningRequestElement.addChildElement("publisherID", "example");
        publisherIdElement.addTextNode(publisherId);

        //Specify the Application Name
        SOAPElement applicationNameElement = requestSigningRequestElement.addChildElement("applicationName", "example");
        applicationNameElement.addTextNode("hash_signing");

        /**
         * Optional Field. If not Specified, system generated values would be used.
         * If Specified, the combination of applicationName and applicationVersion has to be unique across signing request
         */
        SOAPElement applicationVersionElement = requestSigningRequestElement.addChildElement("applicationVersion", "example");
        applicationVersionElement.addTextNode("");

        //Signing Service Name Configured against the account
        SOAPElement signingServiceNameElement = requestSigningRequestElement.addChildElement("signingServiceName", "example");
        signingServiceNameElement.addTextNode(signingServiceName);

        //Base64 encoded form of the hash
        SOAPElement applicationElement = requestSigningRequestElement.addChildElement("application", "example");
        applicationElement.addTextNode(base64EncodedHash);

        //Must be left blank for hash signing.
        SOAPElement commaDelimitedFileNameElement = requestSigningRequestElement.addChildElement("commaDelimitedFileNames", "example");
        commaDelimitedFileNameElement.addTextNode("");

        /**
         *This section is used for fixed cert pool whereby a user can either generate a new cert of use an existing cert from the Pool.
         * Any new generated certificate also gets added to the Pool and can be referenced using the friendlyName
         * This feature is a configurable property per signing service level
         */

        SOAPElement signingCertificateOptionsElement = requestSigningRequestElement.addChildElement("signingCertificateOptions", "example");

        /**
         * Specifies if a new cert is to be generated or to use and existing cert.
         * If New Cert is to be Generated, Set its value to 'GENERATE_NEW_CERT'
         * If existing cert is to be used, set its value to  'USE_FRIENDLY_CERT_NAME'
         */
        SOAPElement signingActionElement = signingCertificateOptionsElement.addChildElement("signingAction", "example");
        signingActionElement.addTextNode("USE_FRIENDLY_CERT_NAME");

        /**
         * Specifies the friendly to use for either generating a new cert of reference an existing cert using this friendly name.
         * If you try generating a new cert with an existing Friendly Name, the existing cert would be used
         */
        SOAPElement certificateFriendlyNameElement = signingCertificateOptionsElement.addChildElement("certificateFriendlyName", "example");
        certificateFriendlyNameElement.addTextNode("alok31112");

        soapMessage.saveChanges();

        /* Print the request message */
        System.out.print("Request SOAP Message = ");
        soapMessage.writeTo(System.out);
        System.out.println();

        return soapMessage;
    }

    /**
     * Method used to print the SOAP Response
     */
    private static void printSOAPResponse(SOAPMessage soapResponse) throws Exception {
        System.out.println("Response: ");
        ByteArrayOutputStream baos = null;
        baos = new ByteArrayOutputStream();
        soapResponse.writeTo(baos);
        String result = baos.toString();

        DocumentBuilder b = DocumentBuilderFactory.newInstance().newDocumentBuilder();

        org.w3c.dom.Document doc = b.parse(new ByteArrayInputStream( result.getBytes() )) ;

        XPath xPath = XPathFactory.newInstance().newXPath();
        NodeList signingSetNode = (NodeList)xPath.evaluate("/Envelope/Body/requestSigningResponse/return/signingSetID",
                doc.getDocumentElement(), XPathConstants.NODESET);
        System.out.println("Signing Set Id: " + signingSetNode.item(0).getFirstChild().getNodeValue() );

        NodeList signingSetStatusNode = (NodeList)xPath.evaluate("/Envelope/Body/requestSigningResponse/return/signingSetStatus",
                       doc.getDocumentElement(), XPathConstants.NODESET);
        System.out.println("signingSetStatus: " + signingSetStatusNode.item(0).getFirstChild().getNodeValue() );

        NodeList signatureNode = (NodeList)xPath.evaluate("/Envelope/Body/requestSigningResponse/return/signature",
                               doc.getDocumentElement(), XPathConstants.NODESET);
        System.out.println("signature: " + signatureNode.item(0).getFirstChild().getNodeValue() );

        NodeList certificateNode = (NodeList)xPath.evaluate("/Envelope/Body/requestSigningResponse/return/certificateInfo/signingCertificates/signingCertificate",
                                      doc.getDocumentElement(), XPathConstants.NODESET);
        for(int i=0; i < certificateNode.getLength(); i++) {
            System.out.println("certificate:\\n " + certificateNode.item(i).getFirstChild().getNodeValue());
        }

    }

}

We use cookies to ensure that we give you the best experience on our website. By using this site, you agree to the Terms of Service.