Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions delivery/common/cwt/README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# CWT Module

The CWT module can be used to perform operations related to CWT tokens such as CWT token generation and validation. The module considers CWT tokens defined as per this [spec](https://www.rfc-editor.org/rfc/rfc8392.html). It exports implementations of CWTValidator class that contains API's to validate CWT tokens.
The CWT module can be used to perform operations related to CWT tokens such as CWT token generation and validation. The module considers CWT tokens defined as per this [spec](https://www.rfc-editor.org/rfc/rfc8392.html). It exports implementations of CWTValidator, CWTGenerator class that contains API's to validate/sign CWT tokens respectively.

## Limitations
- Currently the module only support API's for verification of CWT tokens that are generated using HS256, ES256 algorithm only.
- Currently the module only support API's for signature and verification of CWT tokens that are generated using HS256, ES256, PS256 algorithm only.
- Currently the module only support MAC0 and Sign1 COSE message structure. Refer this [page](https://datatracker.ietf.org/doc/rfc8152/) for more details on CBOR Object Signing and Encryption (COSE).
- As of now, EW do not support KMI to manage verification keys, hence these keys are fetched from property manager user defined variable which might not be a secure way. More details on user defined variables can be found [here](https://techdocs.akamai.com/property-mgr/docs/user-defined-vars)

Expand All @@ -19,6 +19,3 @@ For more information on CWT Module, please refer to the following resources:

## Reporting Issues
If you experience any problems, please raise a Github issue or create a pull request with fixes, suggestions, or code contributions.

### Todo
- [ ] Complete E2E tests for ES256
2 changes: 1 addition & 1 deletion delivery/common/cwt/examples/cwt-es256/bundle.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"edgeworker-version": "0.1",
"description" : "CWT validator example with ES256"
"description" : "CWT generator and validator example with ES256"
}
114 changes: 76 additions & 38 deletions delivery/common/cwt/examples/cwt-es256/cbor-x.js

Large diffs are not rendered by default.

266 changes: 217 additions & 49 deletions delivery/common/cwt/examples/cwt-es256/cwt.js

Large diffs are not rendered by default.

100 changes: 60 additions & 40 deletions delivery/common/cwt/examples/cwt-es256/main.js
Original file line number Diff line number Diff line change
@@ -1,73 +1,93 @@
import { logger } from 'log';
import { CWTUtil, CWTValidator} from './cwt.js';
import { CWTUtil, CWTValidator, CWTGenerator, AlgorithmLabels, ClaimLabels, HeaderLabels} from './cwt.js';
import { crypto, pem2ab } from 'crypto';
import { base16 } from 'encoding';

//Integer keys mapping for CWT payload. This mapping is application specific, However keys from 1-7 are reserved
const claimsLabelMap = {

1: 'iss',
2: 'sub',
3: 'aud',
4: 'exp',
5: 'nbf',
6: 'iat',
7: 'cti',
300: 'wmver',
301: 'wmvnd',
302: 'wmpatlen',
303: 'wmsegduration',
304: 'wmpattern',
305: 'wmid',
306: 'wmopid',
307: 'wmkeyver'
6: 'iat'
};

//advanced options for cwt validator
const cwtOptions = {
//perform header validation
headerValidation: true,
headerValidation: false,
//check token expiry
ignoreExpiration: false,
ignoreExpiration: true,
//check token nbf
ignoreNotBefore: false
ignoreNotBefore: true
};

export const es256PrivKey1 = {
key_ops: ['sign'],
ext: false,
kty: 'EC',
x: 'D5fNFnQYFBOjWa1ndpQK3ZrzXuHD77oGDgPaMNbtZ7s',
y: 'Y4iS6G8atqp3x85xJOfCY997AVWHPy-dEgLk6CaNZ7w',
crv: 'P-256',
d: 'CyJoz5l2IG9cPEXvPATnU3BHrNS1Qx5-dZ4e_Z0H_3M'
};

const es256PubKey1 = `-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAED5fNFnQYFBOjWa1ndpQK3ZrzXuHD
77oGDgPaMNbtZ7tjiJLobxq2qnfHznEk58Jj33sBVYc/L50SAuToJo1nvA==
-----END PUBLIC KEY-----`;

const cwtValidator = new CWTValidator(cwtOptions);

export async function onClientRequest (request) {

try {
// Fetch hmac veification key from Propery Manager
const pubKey = request.getVariable('PMUSER_CWT_ES256_KEY');
const sKey = await crypto.subtle.importKey(
'spki',
pem2ab(pubKey),
const signingKey = await crypto.subtle.importKey(
'jwk',
es256PrivKey1,
{
name: 'HMAC',
hash: 'SHA-256'
name: 'ECDSA',
namedCurve: 'P-256'
},
false,
['verify']
!1,
['sign']
);
//Fetch the Authorization header from request
let cwt = request.getHeader('Authorization');
if (cwt){
cwt = cwt[0];
//replace auth scheme before validating
cwt = cwt.replace('Bearer ','');
//Assumption: CWT token as passed as hex encoded in authorization header. We decode the hex to get the binary
const tokenBuf = base16.decode(cwt,'Uint8Array');
const cwtJSON = await cwtValidator.validate(tokenBuf,[sKey]);
const claims = CWTUtil.claimsTranslate(Object.fromEntries(new Map(cwtJSON.payload)),claimsLabelMap);
logger.log('cwtJSON %s: ',JSON.stringify(claims));
request.respondWith(200, {}, JSON.stringify(claims));
if (request.path == '/token' && request.method == 'POST') {
const claims = { iss: '[email protected]', iat: Date.now(), sub: "[email protected]", aud: ["[email protected]"], exp: Date.now() + 86400, nbf: Date.now() - 86400};
const claimsSet = CWTUtil.claimsTranslate(claims, ClaimLabels);
const signer = {
key: signingKey
};
const cwtToken = await CWTGenerator.sign(claimsSet, signer, { p: CWTUtil.claimsTranslate({ alg: AlgorithmLabels.ES256 }, HeaderLabels)});
const cwtTokenHex = base16.encode(new Uint8Array(cwtToken));
request.respondWith(200, {}, cwtTokenHex);
} else {
//Return bad request of authorization header is not found
request.respondWith(400, {}, 'Authorization header is missing!');
const verifyKey = await crypto.subtle.importKey(
'spki',
pem2ab(es256PubKey1),
{ name: "ECDSA", namedCurve: "P-256" },
false,
['verify']
);
//Fetch the Authorization header from request
let cwtToken = request.getHeader('Authorization');
if (cwtToken){
cwtToken = cwtToken[0];
//replace auth scheme before validating
cwtToken = cwtToken.replace('Bearer ','');
//Assumption: CWT token as passed as hex encoded in authorization header. We decode the hex to get the binary
const tokenBuf = base16.decode(cwtToken,'Uint8Array');
const cwtJSON = await cwtValidator.validate(tokenBuf,[{key: verifyKey}]);
const claims = CWTUtil.claimsTranslate(cwtJSON.payload,claimsLabelMap);
request.respondWith(200, {}, JSON.stringify(Object.fromEntries(claims)));
} else {
//Return bad request of authorization header is not found
request.respondWith(400, {}, 'Authorization header is missing!');
}
}
} catch (error) {
logger.log(error);
request.respondWith(400, {}, error.message);
}
}
}
2 changes: 1 addition & 1 deletion delivery/common/cwt/examples/cwt-hs256/bundle.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"edgeworker-version": "0.1",
"description" : "CWT validator example with HS256"
"description" : "CWT generator and validator example with HS256"
}
Loading