AWS Signing Signature

waseem5
Kilo Expert

Hi,

We are trying to invoke AWS from ServiceNow and need to get signature by using HMAC-SHA26. We want to imitate the methods of encryption from crypto-js. For example, below needs to be coded in ServiceNow scripts: Crypto.HMAC(Crypto.SHA256, dateStamp, "AWS4" + key, { asBytes: true}

We have found below Script Include but unable to locate the exact method within:

  1. AWSRequestSigner
  2. AWSRESTMessage
  3. AWSRESTPostMessage
  4. AWSRESTRequestSigningUtil
  5. FormationRESTActivityBase

If anybody here has any input, it will be of great help!

Thanks in anticipation

Waseem

12 REPLIES 12

Key must be Must be Base64 encoded for GlideCertificateEncryption.generateMac()

https://developer.servicenow.com/dev.do#!/reference/api/orlando/server_legacy/c_GlideC//ertificateEncryptionAPI#r-GCE-GCE

If  Base64 encoded Key is used, GlideCertificateEncryption.generateMac() gave a base64 signature. Below code worked for me:

var shared_secret = "shared_secret";
var authentication_string = "authentication_string";

//Convert to UTF-8 string
shared_secret = encodeURIComponent(shared_secret);

//Key must be Must be Base64 encoded 
shared_secret = GlideStringUtil.base64Encode(shared_secret);

//Convert to UTF-8 
authentication_string = unescape(encodeURIComponent(authentication_string));


var mac = new GlideCertificateEncryption;

//Base64 Signature 
signature = mac.generateMac(shared_secret, "HmacSHA256",authentication_string );

 

 

We resorted to using a custom Node.js API hosted as an Azure Function. To generate hashes, we call this Function from ServiceNow and parse the hash from the response.

anashanifm
Tera Guru

You can use the AWSRESTRequestSigningUtil and follow this procedure to create a signature.

https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html

I'm happy to report that I was able to generate valid pre-signed S3 URLs using the following script in Xplore 4.5. The script uses AWSRESTRequestSigningUtil, of course, but AWSRESTRequestSigningUtil requires the IT Operations Management module in ServiceNow, if I'm not mistake. Also note that the following script is *not* suitable for use in a Script Include. This is only a prototype, and it still needs to be refactored into a proper JS class per c_ScriptIncludes.html.

// thanks to https://gist.github.com/adv0r/1dfaf7999d7aac95d473e65b675496b0
var logList = [];

//Remote settings
var regionName = "us-east-1"; //Replace with your correct AWS region
var bucketName = "mybucket"; //replace with your bucket name
var canonicalUri = "bomgar-ic-setup-32bit-1.6.3.1054.zip"; //replace with the file path you want to GET

//AWS Credentials
var accessKey = "AKIAJN72RZOIQ"; // replace with a valid key
var secretKey = "aWLWPQpWMe3fzFGmDeJhmwKIso"; // replace with a valid key

//Settings
var expires = "604800";
var endpoint = "https://s3.amazonaws.com";
var algorithm = "AWS4-HMAC-SHA256";

//Util
gs.setProperty("aws.rest.debug", "true");
var signingUtil = new AWSRESTRequestSigningUtil();
var signingUtilAlgorithm = "HmacSHA256"; // this was a guess


/* the following 4 tasks are taken from amazon.com sigv4_signing.html
Task 1: Create a Canonical Request for Signature Version 4
Task 2: Create a String to Sign for Signature Version 4
Task 3: Calculate the Signature for AWS Signature Version 4
Task 4: Add the Signature to the HTTP Request */

/*Task 1: Create a Canonical Request for Signature Version 4
Source: sigv4-create-canonical-request.html
var CanonicalRequest =
    HTTPRequestMethod + '\n' +
    CanonicalURI + '\n' +
    CanonicalQueryString + '\n' +
    CanonicalHeaders + '\n' +
    SignedHeaders + '\n' +
    HexEncode(Hash(RequestPayload));*/

// canonical query string
/*Action=ListUsers&Version=2010-05-08&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIDEXAMPLE%2F20150830%2Fus-east-1%2Fiam%2Faws4_request&X-Amz-Date=20150830T123600Z&X-Amz-SignedHeaders=content-type%3Bhost%3Bx-amz-date*/

var dateTimeString = signingUtil.getDateTimeStringForSigningV4(); //yyyyMMddTHHmmssZ
logList.push({"dateTimeString":dateTimeString});

var dateString = signingUtil.getDateStringForSigningV4(); // yyyyMMdd
logList.push({"dateString":dateString});

// AKIDEXAMPLE%2F20150830%2Fus-east-1%2Fiam%2Faws4_request
var credential =
    encodeURIComponent(
      accessKey + "/" + dateString + "/" + regionName + "/" + signingUtil.getService(endpoint) + "/aws4_request"
    );
logList.push({"credential":credential});

// Action=ListUsers&Version=2010-05-08
var queryParameters =
    "X-Amz-Algorithm=" + algorithm + "&"
  + "X-Amz-Credential=" + credential + "&"
  + "X-Amz-Date=" + dateTimeString + "&"
  + "X-Amz-Expires=" + expires + "&"
  + "X-Amz-SignedHeaders=host";
logList.push({"queryParameters":queryParameters});

// canonical headers
/*content-type:application/x-www-form-urlencoded; charset=utf-8\n
host:iam.amazonaws.com\n
my-header1:a b c\n
my-header2:"a b c"\n
x-amz-date:20150830T123600Z\n*/

var headersToSort = [
  {
    "name":"host",
    "value": bucketName + "." + signingUtil.getService(endpoint) + ".amazonaws.com"
  }
];

var canonicalHeadersString = signingUtil.getCanonicalHeadersString(headersToSort);
logList.push({"canonicalHeadersString":canonicalHeadersString});

// signed headers
// content-type;host;x-amz-date\n
var signedHeadersString = signingUtil.getSignedHeadersString(headersToSort);
logList.push({"signedHeadersString":signedHeadersString});

// payload
var payload = "UNSIGNED-PAYLOAD";
logList.push({"payload":payload});

/* CanonicalRequest example from sigv4-query-string-auth.html:
GET
/test.txt
X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIOSFODNN7EXAMPLE%2F20130524%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20130524T000000Z&X-Amz-Expires=86400&X-Amz-SignedHeaders=host
host:examplebucket.s3.amazonaws.com

host
UNSIGNED-PAYLOAD */
var canonicalRequest =
    "GET" + "\n" +
    "/" + canonicalUri + "\n" +
    queryParameters + "\n" +
    canonicalHeadersString + "\n" +
    signedHeadersString + "\n" +
    payload;
logList.push({"canonicalRequest":canonicalRequest});

// digest (hash) of the canonical request with the same algorithm that you used to hash the payload.
var hashedCanonicalRequest = signingUtil.getHashedPayloadString(canonicalRequest, "SHA256");
logList.push({"hashedCanonicalRequest":hashedCanonicalRequest});


/* Task 2: Create a String to Sign for Signature Version 4

StringToSign =
    Algorithm + \n +
    RequestDateTime + \n +
    CredentialScope + \n +
    HashedCanonicalRequest

ExampleStringToSign =
    AWS4-HMAC-SHA256
    20150830T123600Z
    20150830/us-east-1/iam/aws4_request
    f536975d06c0309214f805bb90ccff089219ecd68b2577efef23edd43b7e1a59*/

var credentialScopeString =
    signingUtil.getCredentialScopeString(dateString, endpoint);
logList.push({"credentialScopeString":credentialScopeString});

var stringToSign =
    algorithm + "\n" +
    dateTimeString + "\n" +
    credentialScopeString + "\n" +
    hashedCanonicalRequest;
logList.push({"stringToSign":stringToSign});


/* Task 3: Calculate the Signature for AWS Signature Version 4*/
var signature = signingUtil.getSignatureVersion4(
  endpoint, stringToSign, secretKey, dateString, signingUtilAlgorithm
);
logList.push({"signature":signature});


/* Task 4: Add the Signature to the HTTP Request

querystring = Action=action
querystring += &X-Amz-Algorithm=algorithm
querystring += &X-Amz-Credential= urlencode(access_key_ID + '/' + credential_scope)
querystring += &X-Amz-Date=date
querystring += &X-Amz-Expires=timeout interval
querystring += &X-Amz-SignedHeaders=signed_headers
querystring += &X-Amz-Signature=signature

exampleQueryString = Action=ListUsers&Version=2010-05-08&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIDEXAMPLE%2F20150830%2Fus-east-1%2Fiam%2Faws4_request&X-Amz-Date=20150830T123600Z&X-Amz-Expires=60&X-Amz-SignedHeaders=content-type%3Bhost&X-Amz-Signature=37ac2f4fde00b0ac9bd9eadeb459b1bbee224158d66e7ae5fcadb70b2d181d02

The following is an example presigned URL. The line feeds are added for readability.

https://examplebucket.s3.amazonaws.com/test.txt?
X-Amz-Algorithm=AWS4-HMAC-SHA256&
X-Amz-Credential=AKIAIOSFODNN7EXAMPLE%2F20130524%2Fus-east-1%2Fs3%2Faws4_request&
X-Amz-Date=20130524T000000Z&
X-Amz-Expires=86400&
X-Amz-SignedHeaders=host&
X-Amz-Signature=aeeed9bbccd4d02ee5c0109b86d86835f995330da4c265957d157751f604d404

(amazon.com, sigv4-query-string-auth.html)
*/

queryParameters += "&X-Amz-Signature=" + signature;
logList.push({"queryParameters":queryParameters});

var presignedUrl = "https://" + bucketName + "." + signingUtil.getService(endpoint) + ".amazonaws.com" + "/" + canonicalUri + "?" + queryParameters;
logList.push({"presignedUrl":presignedUrl});
JSON.stringify(logList);

Which plugin we have to activate to get "AWSRESTRequestSigningUtil"?