Generate Digital Signature for Hash
This API allows users to compute the digital signature for a given hash using a specified signing policy and key details.
Before you begin
- Configure the signing policy with relevant details, ensuring mapping to the enrolled certificate (also identified as the signing key on the signing policy page).
- Input payload formation.
The byte lengths for various hashing algorithms and the additional bytes appended when sent from a Cryptographic Service Provider (CSP) or PKCS#11. It also includes the initial bytes for ASN.1 encoding for each algorithm and a script change to handle these for API based signing from the tools apart from CSP/PKCS#11.
As the API-based signing solution requires the input payload to be pre-processed, rather than relying on CSP/PKCS#11. To handle hashing and ASN.1 encoding, it is necessary to generate the file hash using the required hash algorithm and then apply the appropriate ASN.1 encoding in accordance with the selected algorithm. The resulting ASN.1-encoded hash must be provided as the input to the API. This approach ensures that the data sent to the API is in the correct format for signature generation and remains compatible with standard cryptographic verification processes.
Hashing Algorithms: ASN.1 Encoding & Forming Payload
Hashing Algorithm Byte Lengths:
The file's hash is computed using the specified hashing algorithm.
- SHA1: 20 bytes
- SHA256: 32 bytes
- SHA384: 48 bytes
- SHA512: 64 bytes
ASN.1 Encoding Initial Bytes:
- SHA1: {0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1a,0x05,0x00,0x04}
- SHA256: {0x30,0x31,0x30,0x0D,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0x04}
- SHA384: {0x30,0x41,0x30,0x0D,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x02,0x05,0x00,0x04}
- SHA512: {0x30,0x51,0x30,0x0D,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03,0x05,0x00,0x04}
The input of the API follows the below format for the field "fileHashContent".
- SHA1: 14 + 1 + 20 bytes
- SHA256: 18 + 1 + 32 bytes
- SHA384: 18 + 1 + 48 bytes
- SHA512: 18 + 1 + 64 bytes
- Python:
python3 APIBasedEncodingPythonFile.py /path/to/your/file SHA256
For Example:import hashlib import base64 import sys import os # ASN.1 padded bytes per hash algorithm PADDING_BYTES = { 'SHA1': bytes([0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1a,0x05,0x00,0x04]), 'SHA256': bytes([0x30,0x31,0x30,0x0D,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0x04]), 'SHA384': bytes([0x30,0x41,0x30,0x0D,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x02,0x05,0x00,0x04]), 'SHA512': bytes([0x30,0x51,0x30,0x0D,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03,0x05,0x00,0x04]), } def compute_file_hash(filepath, algorithm): algo_map = { 'SHA1': 'sha1', 'SHA256': 'sha256', 'SHA384': 'sha384', 'SHA512': 'sha512', } if algorithm.upper() not in algo_map: raise ValueError(f"Unsupported algorithm: {algorithm}") hash_func = hashlib.new(algo_map[algorithm.upper()]) with open(filepath, 'rb') as file: while chunk := file.read(8192): hash_func.update(chunk) return hash_func.digest() def create_asn1_hash_encoded(hash_bytes, algorithm): padding = PADDING_BYTES[algorithm.upper()] length_byte = bytes([len(hash_bytes)]) # One byte denoting the length full_bytes = padding + length_byte + hash_bytes return base64.b64encode(full_bytes) if __name__ == "__main__": if len(sys.argv) < 3: print("Usage: python script.py <file_path> <hash_algorithm>") print("Hash Algorithm: SHA1 | SHA256 | SHA384 | SHA512") sys.exit(1) file_path = sys.argv[1] hash_algo = sys.argv[2] if not os.path.isfile(file_path): print("Error: File not found:", file_path) sys.exit(1) try: hash_bytes = compute_file_hash(file_path, hash_algo) fileHashContent = create_asn1_hash_encoded(hash_bytes, hash_algo) print("fileHashContent (Base64):", fileHashContent.decode()) except Exception as e: print("Error:", str(e)) sys.exit(1) - Bash:
./APIBasedASN1EncodingBashFile.sh /path/to/your/file SHA256
#!/bin/bash set -e # Check args if [[ $# -ne 2 ]]; then echo "Usage: $0 <file_path> <SHA1|SHA256|SHA384|SHA512>" exit 1 fi FILE="$1" ALG="${2^^}" # Validate file if [[ ! -f "$FILE" ]]; then echo "File not found: $FILE" exit 1 fi # ASN.1 Padding Hex Map declare -A PAD_MAP PAD_MAP["SHA1"]="3021300906052b0e03021a050004" PAD_MAP["SHA256"]="3031300d0609608648016503040201050004" PAD_MAP["SHA384"]="3041300d0609608648016503040202050004" PAD_MAP["SHA512"]="3051300d0609608648016503040203050004" if [[ -z "${PAD_MAP[$ALG]}" ]]; then echo "Unsupported algorithm. Use SHA1, SHA256, SHA384, or SHA512." exit 1 fi # Temp working directory TMP_DIR=$(mktemp -d) trap "rm -rf $TMP_DIR" EXIT ASN1_FILE="$TMP_DIR/asn1.bin" LEN_FILE="$TMP_DIR/len.bin" HASH_FILE="$TMP_DIR/hash.bin" FINAL_FILE="$TMP_DIR/final.bin" # 1. Write ASN.1 padding to binary file echo "${PAD_MAP[$ALG]}" | xxd -r -p > "$ASN1_FILE" # 2. Compute hash bytes and save to file openssl dgst "-$ALG" -binary "$FILE" > "$HASH_FILE" # 3. Calculate hash length in bytes and write as a single byte HASH_LEN=$(stat -c %s "$HASH_FILE") printf "%02x\n" "$HASH_LEN" | xxd -r -p > "$LEN_FILE" # 4. Concatenate all to final binary file cat "$ASN1_FILE" "$LEN_FILE" "$HASH_FILE" > "$FINAL_FILE" # 5. Base64 encode final bytes fileHashContent=$(base64 "$FINAL_FILE") # 6. Output echo "fileHashContent (Base64):" echo "$fileHashContent" - PowerShell:./APIBasedASN1EncodingPSFile.ps1 -FilePath /path/to/your/file -HashAlgorithm SHA256
param ( [Parameter(Mandatory=$true)][string]$FilePath, [Parameter(Mandatory=$true)][ValidateSet("SHA1", "SHA256", "SHA384", "SHA512")][string]$HashAlgorithm ) # Define ASN.1 Padded Bytes for each algorithm $paddingBytesMap = @{ "SHA1" = @(0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1a,0x05,0x00,0x04) "SHA256" = @(0x30,0x31,0x30,0x0D,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0x04) "SHA384" = @(0x30,0x41,0x30,0x0D,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x02,0x05,0x00,0x04) "SHA512" = @(0x30,0x51,0x30,0x0D,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03,0x05,0x00,0x04) } if (-not (Test-Path $FilePath)) { Write-Error "File not found: $FilePath" exit 1 } # Compute file hash $hashBytes = Get-FileHash -Path $FilePath -Algorithm $HashAlgorithm | Select-Object -ExpandProperty Hash $hashBinary = [byte[]]::new($hashBytes.Length / 2) for ($i = 0; $i -lt $hashBinary.Length; $i++) { $hashBinary[$i] = [Convert]::ToByte($hashBytes.Substring($i * 2, 2), 16) } # Get ASN.1 padding $paddingBytes = [byte[]]$paddingBytesMap[$HashAlgorithm] # Length byte for the hash $lengthByte = [byte[]]@($hashBinary.Length) # Final Byte Array = padding + lengthByte + hash $finalBytes = $paddingBytes + $lengthByte + $hashBinary # Base64 encode the final bytes $fileHashContent = [Convert]::ToBase64String($finalBytes) # Output Write-Host "fileHashContent (Base64):" Write-Output $fileHashContent
Request Structure
| Endpoint: | /code-signing-generate-hash |
| Type: | POST |
| Sample URL: | https://<IP/HostName/TenantName>:<GWPORT>/avxapi/code-signing-generate-hash?gwsource=externalTo understand the elements of the sample URL, click here. |
| Content-Type: | application/json |
| Name | Description |
|---|---|
| sessionId
|
(Mandatory) After successfully logging in, a unique
identifier assigned to a user's session after successful
authentication. The session ID remains valid until it expires.
The session ID is a string value. Example: "ce7f1a14-2bf9-4e4a-89a8-bc780a255813" |
| username
|
(Mandatory) AppViewX login username, represented as a string
value. Example: "User" |
| password
|
(Mandatory) AppViewX login username, represented as a string
value. Example: "AppViewX@123" |
| Payload | (Mandatory) Input data for request body in application/json format. For payload details, see Payload section. |
Payload
| Name | Description |
|---|---|
| signingPolicy
|
(Mandatory) Enter the signing policy for code signing which is a
string value. Example: "Test_Policy_01" |
| signingKey
|
(Mandatory) Enter the signing key for code signing which is a
string value. Example: "Google CA Code Signing Certificate_Demo=A5:09:C1:6C:3F:72: 81:61:59:3A:58:EA:ED:33:11:ED:64:91:DC" |
| versionNumber
|
(Mandatory) Enter the version number for code signing, which
should be a string value. Example: "v1" |
| description
|
(Mandatory) Description of the hash generation, provided as a
string value. Example: "Hash Signing" |
| signedType
|
(Mandatory) Select the code signed type, a string that specifies
Hash Based sign. Example: "Hash Based Signing" |
| fileHashContent
|
(Mandatory) Enter the hash file content as a string value.
Example: "MDEwDQYJYIZIAWUDBAIBBQAEIPw9hz6RJNKrng4tnsFCUGKXA6qAyxRe2kFVOjdpfTMw" |
| signatureType
|
(Optional) This ensures compliance with a designated signature
format while also allowing for potential support of additional
signing types in the future. Example: "RAW" |
| addOnFields
|
(Optional) Specify additional fields needed for code signing.
Example: "addOnFields": [{"Version":"V1"},{"Build":"1"}] |
Response Structure
- Status Code: 200 OK
- Message: Successful
- Headers:
- Content-Type: application/json
| Name | Description |
|---|---|
| response | Contains the response attributes for generating the signature for the code signing request. |
| message | Success message or failure description in case of error. |
| appStatusCode | Application specific status code for the response. Will be non-null for failure response. |
| tags | More info in case of failure response. |
Status Codes
| HTTP Code | appStatusCode | Response Message |
|---|---|---|
| 200 OK | null | Successful |
| 403 Forbidden | CODE_SIGNING_0032 | Permissions are not there to sign the hash of a file |
| 500 Internal Server Error | CODE_SIGNING_0062 | IP provided is invalid |
| 500 Internal Server Error | CODE_SIGNING_0083 | The retrieved IP address is not valid. The selected policy does not support the obtained IP address. |
| 500 Internal Server Error | CODE_SIGNING_0063 | Your chosen signing type is not supported by the selected policy |
| 500 Internal Server Error | CODE_SIGNING_0056 | Signing Policy Info is not present in the Database for the given input |
| 500 Internal Server Error | CODE_SIGNING_0070 | Signing Key is not mapped to the given policy. |
| 500 Internal Server Error | CODE_SIGNING_0073 | Certificate is not present in the cert inventory |
| 500 Internal Server Error | CODE_SIGNING_0021 | Error in updating the signed data |
| 500 Internal Server Error | CODE_SIGNING_0066 | Failed to convert to json string |
| 500 Internal Server Error | CODE_SIGNING_0067 | Failed to encrypt |
| 500 Internal Server Error | CODE_SIGNING_0020 | Error in generating the signed file |
| 400 Bad Request | CODE_SIGNING_00222 | Add-on fields are not configured for the given policy. |
| 400 Bad Request | CODE_SIGNING_0082 | Mandatory fields are missing in the Add-ons Section. |
| 400 Bad Request | CODE_SIGNING_00225 | Multiple Add-on fields within a single key-value pair is not allowed. |
| 400 Bad Request | CODE_SIGNING_00223 | Provided Add-on fields are not configured for the given policy. |
| 400 Bad Request | CODE_SIGNING_0080 | Wrong Input Payload for the text fields in the text block. |
| 400 Bad Request | CODE_SIGNING_0081 | Invalid Number added in the Add-ons section. |
| 500 Internal Server Error | CODE_SIGNING_00220 | Your chosen signature type is currently not supported. |
Sample Request/Response
To generate a hash for code signing using code-signing-generate-hash API.
https://<IP/HostName/TenantName>:<GWPORT>/avxapi/code-signing-generate-hash?gwsource=external{
"payload": {
"signingPolicy": "Hash_Policy",
"signingKey": "AppViewX Private Ltd=56:37:33:0E:B1:7D:E4:69:E7:8E:CF:83:56:59:43:93:DD:18:B4",
"description": "Hash Signing",
"signedType": "Hash Based Signing",
"fileHashContent": "MDEwDQYJYIZIAWUDBAIBBQAEIPw9hz6RJNKrng4tnsFCUGKXA6qAyxRe2kFVOjdpfTMw",
"signatureType": "RAW",
"addOnFields": [
{
"Version": "V1"
},
{
"Build_No": "1"
}
]
}
}{
"response": "gutIcFnlzbTT7slB1wrOAbMPzhgFszs8nA1DpMLE/7BcAP39vbgIOCIj1rlmM6bSnBl1bJ3U3CMSWqphEu8KzN9gcCknGTyAOJxEiIXOmi0P9ernL4knxoGnDe//89/rC3drt4XqLahHF7mMKrXLCLGqg0UTpOzUM0ZxQTucz4Z2iWipH3R3wNq4gYB4EijPXkp+7D0Q2PGaIiy9/1LhGzwvappbqU9QBFu3Nkr40jepEs7dGcEFYlw4E1spH+gcJsFEAN1H3UToP6zDiBSEq0ZiwXj0mU+pJGxIG49x7jOaDJgAS+p6/ll9eulwRk7Ft4NXoXwWkvYZTx2HAMz0mg==",
"message": null,
"appStatusCode": null,
"tags": null,
"headers": null
}Reference
- IP/HostName/TenantName: Replace with the actual IP address, hostname,
or tenant name based on the specific configuration in AppViewX.
- IP: A unique identifier assigned to each device connected to
a computer network that uses the Internet Protocol for communication
The IP address will be included in the endpoint URL for an on-prem deployment.
- HostName: A human-readable label assigned to a device (host)
on a network
The hostname will be included in the endpoint URL for an on-prem deployment.
- TenantName: An identifier label for a tenant given to
indicate which tenant's data the API request will
access/modify
The tenant name will be included in the endpoint URL for a SaaS deployment.
- IP: A unique identifier assigned to each device connected to
a computer network that uses the Internet Protocol for communication
- GWPORT: AppViewX gateway port
A gateway port refers to a network port through which data is sent and received to communicate with a gateway in an on-prem deployment.
Example: 31443
- avxapi: Path parameter value (static) that is part of the endpoint's URL
- Endpoint: Endpoint of the API, for example: execute-hook
- gwsource: Source or origin of a gateway, for example: external.