mirror of
https://github.com/tlsnotary/PageSigner.git
synced 2026-01-08 06:14:02 -05:00
PageSigner v3 release. Based on the TLSNotary protocol which supports TLS 1.2+
This commit is contained in:
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "core/twopc/circuits"]
|
||||
path = core/twopc/circuits
|
||||
url = https://github.com/tlsnotary/circuits
|
||||
29
README
29
README
@@ -1,22 +1,15 @@
|
||||
----------------------------------------------------------------
|
||||
UPDATE: Jul 2021
|
||||
A flaw in PageSigner has been brought to our attention which allows to create forged proofs under certain conditions.
|
||||
We are working on a mitigation.
|
||||
PageSigner - a cryptographically secure webpage screenshot tool.
|
||||
|
||||
Read more here:
|
||||
https://github.com/tlsnotary/pagesigner/issues/46
|
||||
----------------------------------------------------------------
|
||||
PageSigner is a Chromium extension implementing a client for the TLSNotary protocol.
|
||||
|
||||
You can install PageSigner from Chrome webstore:
|
||||
|
||||
https://chrome.google.com/webstore/detail/pagesigner/abblaaeblmamacadkdmnejjikbdkemcj
|
||||
|
||||
|
||||
PageSigner works with many Chromium-based browsers (e.g. Chromium, Vivaldi, Brave, Google Chrome)
|
||||
Or you can install it by cloning this repo with:
|
||||
|
||||
You can load PageSigner from the source files of this repo this way:
|
||||
|
||||
1. go to chrome://extensions and Enable "Developer mode"
|
||||
|
||||
2. Click "Load unpacked"
|
||||
|
||||
3. Navigate inside pagesigner's top folder and click Open.
|
||||
|
||||
-----
|
||||
Firefox addon creation is not supported anymore due to missing API in Firefox.
|
||||
- git clone --recurse-submodules https://github.com/tlsnotary/pagesigner
|
||||
- go to chrome://extensions and Enable "Developer mode"
|
||||
- Click "Load unpacked"
|
||||
- Navigate inside pagesigner's top folder and click Open.
|
||||
|
||||
15
background.html
Normal file
15
background.html
Normal file
@@ -0,0 +1,15 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<script src="core/third-party/simple-js-ec-math.js"></script>
|
||||
<script src="core/third-party/sodium.js"></script> <!--dont put this any lower in the list or youll get require() not defined -->
|
||||
<script src="core/third-party/nacl-fast.js"></script>
|
||||
<script src="core/third-party/fastsha256.js"></script>
|
||||
<script src="core/third-party/cbor.js"></script>
|
||||
<script src="core/third-party/cose.js"></script>
|
||||
<script src="core/twopc/circuits/casmbundle.js"></script>
|
||||
<script type="module" src="core/Main.js"></script>
|
||||
<!-- <script type="module" src="core/test.js"></script> -->
|
||||
</body>
|
||||
</html>
|
||||
144
core/FirstTimeSetup.js
Normal file
144
core/FirstTimeSetup.js
Normal file
@@ -0,0 +1,144 @@
|
||||
import {wait} from './utils.js';
|
||||
|
||||
// class FakeFS imitates node.js's fs.readFileSync() by
|
||||
// reading the files in advance and outputting their content when readFileSync() is called
|
||||
class FakeFS{
|
||||
constructor(){
|
||||
this.fileList = {}; // {fileName: <text string>}
|
||||
}
|
||||
|
||||
// on init we read all .casm and .txt files in core/twopc/circuits
|
||||
async init(){
|
||||
const that = this;
|
||||
await new Promise(function(resolve) {
|
||||
chrome.runtime.getPackageDirectoryEntry(function(root){
|
||||
root.getDirectory('core/twopc/circuits', {create: false}, function(dir) {
|
||||
dir.createReader().readEntries(async function(results) {
|
||||
for (let i=0; i < results.length; i+=1){
|
||||
const e = results[i];
|
||||
if (e.name.endsWith('.casm') || e.name.endsWith('.txt')){
|
||||
const url = chrome.extension.getURL('core/twopc/circuits/'+e.name);
|
||||
const resp = await fetch(url);
|
||||
const text = await resp.text();
|
||||
that.fileList[e.name] = text;
|
||||
}
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// feed back all data read in init()
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
readFileSync(path, _unused){
|
||||
return this.fileList[path];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// FirstTimeSetup.start() is invoked once on first install. It assembles the circuits,
|
||||
// serializes them into a compact binary format and stores them in the browser cache.
|
||||
// All future invocations of Pagesigner use these serialized cached circuits.
|
||||
export class FirstTimeSetup{
|
||||
async start(pm){
|
||||
const worker = new Worker(chrome.extension.getURL('core/twopc/webWorkers/serializeCircuits.js'));
|
||||
console.log('parsing circuits, this is done only once on first launch and will take ~30 secs');
|
||||
console.time('parsing raw circuits');
|
||||
const obj = {};
|
||||
const oldfs = window['fs'];
|
||||
window['fs'] = new FakeFS();
|
||||
await window['fs'].init();
|
||||
// start from the last circuits in order to give the user a quicker initial update
|
||||
for (let n=1; n < 7; n++){
|
||||
const i = 7-n;
|
||||
const text = CASM.parseAndAssemble('c'+i+'.casm');
|
||||
const newobj = await new Promise(function(resolve) {
|
||||
worker.onmessage = function(event) {
|
||||
let newobj = event.data.obj;
|
||||
newobj['gatesBlob'] = new Uint8Array(event.data.blob);
|
||||
resolve(newobj);
|
||||
};
|
||||
worker.postMessage({'text': text});
|
||||
});
|
||||
obj[i] = newobj;
|
||||
pm.update('first_time', {'current': n, 'total': 6});
|
||||
await wait(100); // make sure update reaches popup
|
||||
}
|
||||
window['fs'] = oldfs;
|
||||
console.timeEnd('parsing raw circuits');
|
||||
return obj;
|
||||
}
|
||||
|
||||
parseCircuitFirstTime(text){
|
||||
const obj = {};
|
||||
// we don't do any sanity/formatting checks because the circuits
|
||||
// were output by casm.js and have a well-defined structure
|
||||
const rows = text.split('\n');
|
||||
obj['gatesCount'] = Number(rows[0].split(' ')[0]);
|
||||
console.log('obj[\'gatesCount\']', obj['gatesCount']);
|
||||
obj['wiresCount'] = Number(rows[0].split(' ')[1]);
|
||||
obj['notaryInputSize'] = Number(rows[1].split(' ')[1]);
|
||||
obj['clientInputSize'] = Number(rows[1].split(' ')[2]);
|
||||
obj['outputSize'] = Number(rows[2].split(' ')[1]);
|
||||
|
||||
// each gate is serialized as
|
||||
// 1 byte: gate type XOR==0 AND==1 INV==2
|
||||
// 3 bytes: 1st input wire number
|
||||
// 3 bytes: 2nd input wire number
|
||||
// 3 bytes: output wire number
|
||||
const gateByteSize = 10;
|
||||
const opBytes = {'XOR': 0, 'AND': 1, 'INV': 2};
|
||||
// first 3 rows are not gates but metadata
|
||||
const blob = new Uint8Array((rows.length-3)*gateByteSize);
|
||||
let blobOffset = 0;
|
||||
let andCount = 0;
|
||||
for (let i=0; i < (rows.length-3); i++){
|
||||
const gate = rows[3+i];
|
||||
const tokens = gate.split(' ');
|
||||
const op = tokens[tokens.length-1];
|
||||
const opByte = opBytes[op];
|
||||
blob.set([opByte], blobOffset);
|
||||
blobOffset+=1;
|
||||
if (op === 'XOR' || op === 'AND'){
|
||||
const in1 = this.intToThreeBytes(tokens[tokens.length-4]);
|
||||
const in2 = this.intToThreeBytes(tokens[tokens.length-3]);
|
||||
const out = this.intToThreeBytes(tokens[tokens.length-2]);
|
||||
blob.set(in1, blobOffset);
|
||||
blobOffset+=3;
|
||||
blob.set(in2, blobOffset);
|
||||
blobOffset+=3;
|
||||
blob.set(out, blobOffset);
|
||||
blobOffset+=3;
|
||||
if (op == 'AND'){
|
||||
andCount+=1;
|
||||
}
|
||||
}
|
||||
else if (op === 'INV'){
|
||||
const in1 = this.intToThreeBytes(tokens[tokens.length-3]);
|
||||
const out = this.intToThreeBytes(tokens[tokens.length-2]);
|
||||
blob.set(in1, blobOffset);
|
||||
blobOffset+=3;
|
||||
blob.set([0,0,0], blobOffset);
|
||||
blobOffset+=3;
|
||||
blob.set(out, blobOffset);
|
||||
blobOffset+=3;
|
||||
}
|
||||
else {
|
||||
throw('unknown op');
|
||||
}
|
||||
}
|
||||
obj['andGateCount'] = andCount;
|
||||
obj['gatesBlob'] = blob;
|
||||
return obj;
|
||||
}
|
||||
|
||||
intToThreeBytes(i){
|
||||
const byteArray = Array(3);
|
||||
byteArray[0] = (i >> 16) & 0xFF;
|
||||
byteArray[1] = (i >> 8) & 0xFF;
|
||||
byteArray[2] = i & 0xFF;
|
||||
return byteArray;
|
||||
}
|
||||
}
|
||||
1073
core/Main.js
Normal file
1073
core/Main.js
Normal file
File diff suppressed because it is too large
Load Diff
54
core/ProgressMonitor.js
Normal file
54
core/ProgressMonitor.js
Normal file
@@ -0,0 +1,54 @@
|
||||
// class ProgressMonitor receives progress information about client's garbling,
|
||||
// evaluation, blob upload, blob download. It dispatches progress status messages
|
||||
// periodically or when queried.
|
||||
// because Chrome has a bug and does not remove onMessage listener, we
|
||||
// use only one ProgressMonitor and reset its state when a new notarization
|
||||
// session starts
|
||||
|
||||
export class ProgressMonitor{
|
||||
constructor(){
|
||||
this.progress = {
|
||||
download: {},
|
||||
upload: {},
|
||||
garbling: {},
|
||||
last_stage: {},
|
||||
first_time: {},
|
||||
};
|
||||
// progress listeners may ask to give the current progress state
|
||||
const that = this;
|
||||
chrome.runtime.onMessage.addListener(function(data) {
|
||||
if (data.destination != 'progress monitor') return;
|
||||
chrome.runtime.sendMessage({
|
||||
destination: 'progress listeners',
|
||||
progress: that.progress
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
init(){
|
||||
this.progress = {
|
||||
download: {},
|
||||
upload: {},
|
||||
garbling: {},
|
||||
last_stage: {},
|
||||
first_time: {},
|
||||
};
|
||||
}
|
||||
|
||||
// update is called with updates progress information
|
||||
update(type, obj){
|
||||
this.progress[type] = obj;
|
||||
chrome.runtime.sendMessage({
|
||||
destination: 'progress listeners',
|
||||
progress: this.progress
|
||||
});
|
||||
}
|
||||
|
||||
// destroy de-registers listeners
|
||||
// doesn't do anything because of what seems like a Chrome bug.
|
||||
destroy(){
|
||||
// TODO it seems like Chrome does not remove onMessage listener
|
||||
chrome.runtime.onMessage.removeListener(this.listener);
|
||||
}
|
||||
}
|
||||
262
core/Socket.js
Normal file
262
core/Socket.js
Normal file
@@ -0,0 +1,262 @@
|
||||
// The only way to determine if the server is done sending data is to check that out receiving
|
||||
// buffer has nothing but complete TLS records i.e. that there is no incomplete TLS records
|
||||
// However it was observed that in cases when getting e.g. zip files, some servers first send HTTP header as one
|
||||
// TLS record followed by the body as another record(s)
|
||||
// That's why after receiving a complete TLS record we wait to get some more data
|
||||
// This extra waiting must not be done for the handshake messages to avoid adding latency and having the handshake
|
||||
// dropped by the server
|
||||
// We do not communicate directly with the server but we send messages to the helper app
|
||||
// It is the helper app which opens a TCP socket and sends/receives data
|
||||
|
||||
import {global} from './globals.js';
|
||||
import {ba2str, b64decode, concatTA, b64encode, str2ba, ba2int} from './utils.js';
|
||||
|
||||
export class Socket {
|
||||
constructor(name, port){
|
||||
this.name = name;
|
||||
this.port = port;
|
||||
this.uid = Math.random().toString(36).slice(-10);
|
||||
|
||||
this.buffer = new Uint8Array();
|
||||
// connect will throw if we couldnt establish a connection to the server for this long
|
||||
this.connectTimeout = 5 * 1000;
|
||||
// recv() will reject if no data was seen for this long
|
||||
this.noDataTimeout = 5 * 1000;
|
||||
// close the socket after this time, even if it is in the middle of receiving data
|
||||
this.lifeTime = 40 * 1000;
|
||||
// delay after which we make a final check of the receicing buffer and if there was no data,
|
||||
// from the server, the we consider the data transmission finished
|
||||
this.delayBeforeFinalIteration = 500;
|
||||
this.wasClosed = false;
|
||||
this.backendPort = 20022;
|
||||
}
|
||||
|
||||
async connect() {
|
||||
const that = this;
|
||||
let timer;
|
||||
const response = await new Promise(async function(resolve, reject) {
|
||||
// dont wait for connect for too long
|
||||
timer = setTimeout(function() {
|
||||
reject('Unable to connect to the webserver. Please check your internet connection.');
|
||||
return;
|
||||
}, that.connectTimeout);
|
||||
|
||||
const msg = {'command': 'connect','args': {'name': that.name,'port': that.port},'uid': that.uid};
|
||||
if (global.usePythonBackend){
|
||||
const url = 'http://127.0.0.1:' + that.backendPort;
|
||||
const payload = JSON.stringify(msg);
|
||||
try{
|
||||
var req = await fetch (url, {method:'POST', body: str2ba(payload).buffer, cache: 'no-store'});
|
||||
}
|
||||
catch (error) {
|
||||
reject('connection error');
|
||||
return;
|
||||
}
|
||||
const text = new Uint8Array (await req.arrayBuffer());
|
||||
const response = ba2str(text);
|
||||
resolve(JSON.parse(response));
|
||||
return;
|
||||
}
|
||||
else {
|
||||
chrome.runtime.sendMessage(global.appId, msg, function(response) {resolve(response);});
|
||||
}
|
||||
})
|
||||
.catch(function(e){
|
||||
throw(e);
|
||||
});
|
||||
|
||||
// we need to access runtime.lastError to prevent Chrome from complaining
|
||||
// about unchecked error
|
||||
chrome.runtime.lastError;
|
||||
clearTimeout(timer);
|
||||
if (response == undefined){
|
||||
throw (undefined);
|
||||
}
|
||||
if (response.retval != 'success') {
|
||||
// throw(response.retval)
|
||||
}
|
||||
// else if (response.retval == 'success') {
|
||||
setTimeout(function() {
|
||||
if (! that.wasClosed)
|
||||
that.close();
|
||||
}, that.lifeTime);
|
||||
// endless data fetching loop for the lifetime of this Socket
|
||||
that.fetchLoop();
|
||||
return 'ready';
|
||||
}
|
||||
|
||||
async send(data_in) {
|
||||
var msg = {'command': 'send', 'args': {'data': Array.from(data_in)}, 'uid': this.uid};
|
||||
if (global.usePythonBackend){
|
||||
msg.args.data = Array.from(b64encode(msg.args.data));
|
||||
await fetch('http://127.0.0.1:20022', {method:'POST', body: JSON.stringify(msg),
|
||||
cache: 'no-store'});
|
||||
}
|
||||
else{
|
||||
chrome.runtime.sendMessage(global.appId, msg);
|
||||
}
|
||||
}
|
||||
|
||||
// poll the backend for more data
|
||||
async fetchLoop() {
|
||||
if (this.wasClosed) {
|
||||
return;
|
||||
}
|
||||
var that = this;
|
||||
var response = await new Promise(async function(resolve){
|
||||
var msg = {'command': 'recv', 'uid': that.uid};
|
||||
if (global.usePythonBackend){
|
||||
var req = await fetch('http://127.0.0.1:20022', {method:'POST', body: JSON.stringify(msg),
|
||||
cache: 'no-store'});
|
||||
var text = new Uint8Array(await req.arrayBuffer());
|
||||
var response = JSON.parse(ba2str(text));
|
||||
if (response.data.length > 0){
|
||||
response.data = Array.from(b64decode(response.data));
|
||||
}
|
||||
resolve(response);
|
||||
}
|
||||
else {
|
||||
chrome.runtime.sendMessage(global.appId, msg, function(response) {resolve(response);});
|
||||
}
|
||||
});
|
||||
if (response.data.length > 0){
|
||||
console.log('fetched some data', response.data.length, that.uid);
|
||||
that.buffer = concatTA(that.buffer, new Uint8Array(response.data));
|
||||
}
|
||||
setTimeout(function() {
|
||||
that.fetchLoop();
|
||||
}, 100);
|
||||
}
|
||||
|
||||
// fetchLoop has built up the recv buffer
|
||||
// check if there are complete records in the buffer,return them if yes or wait some more if no
|
||||
recv (is_handshake) {
|
||||
if (is_handshake == undefined) {
|
||||
is_handshake = false;
|
||||
}
|
||||
var that = this;
|
||||
return new Promise(function(resolve, reject) {
|
||||
var dataLastSeen = new Date().getTime();
|
||||
var complete_records = new Uint8Array();
|
||||
var buf = new Uint8Array();
|
||||
var resolved = false;
|
||||
var lastIteration = false;
|
||||
|
||||
function finished_receiving() {
|
||||
console.log('recv promise resolving', that.uid);
|
||||
resolved = true;
|
||||
resolve(complete_records);
|
||||
}
|
||||
|
||||
var check = function() {
|
||||
var now = new Date().getTime();
|
||||
if ((now - dataLastSeen) > that.noDataTimeout){
|
||||
reject('recv: no data timeout');
|
||||
return;
|
||||
}
|
||||
// console.log('check()ing for more data', uid);
|
||||
if (resolved) {
|
||||
console.log('returning because resolved');
|
||||
return;
|
||||
}
|
||||
if (that.buffer.length === 0) {
|
||||
if (lastIteration){
|
||||
finished_receiving();
|
||||
return;
|
||||
}
|
||||
setTimeout(function() {check();}, 100);
|
||||
return;
|
||||
}
|
||||
// else got new data
|
||||
if (lastIteration){
|
||||
console.log('more data received on last iteration', that.uid);
|
||||
lastIteration = false;
|
||||
}
|
||||
console.log('new data in check', that.buffer.length);
|
||||
dataLastSeen = now;
|
||||
buf = concatTA(buf, that.buffer);
|
||||
that.buffer = new Uint8Array();
|
||||
const rv = that.check_complete_records(buf);
|
||||
complete_records = concatTA(complete_records, rv.comprecs);
|
||||
if (!rv.is_complete) {
|
||||
console.log('check_complete_records failed', that.uid);
|
||||
buf = rv.incomprecs;
|
||||
setTimeout(function() {check();}, 100);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
console.log('got complete records', that.uid);
|
||||
if (is_handshake) {
|
||||
finished_receiving();
|
||||
return;
|
||||
}
|
||||
else {
|
||||
console.log('in recv waiting for an extra second', that.uid);
|
||||
buf = new Uint8Array();
|
||||
// give the server another second to send more data
|
||||
lastIteration = true;
|
||||
setTimeout(function() {check();}, that.delayBeforeFinalIteration);
|
||||
}
|
||||
}
|
||||
};
|
||||
check();
|
||||
})
|
||||
.catch(function(error){
|
||||
throw(error);
|
||||
});
|
||||
}
|
||||
|
||||
async close() {
|
||||
this.wasClosed = true;
|
||||
var msg = {'command': 'close','uid': this.uid};
|
||||
console.log('closing socket', this.uid);
|
||||
if (global.usePythonBackend){
|
||||
await fetch('http://127.0.0.1:20022', {method:'POST', body: JSON.stringify(msg),
|
||||
cache: 'no-store'});
|
||||
}
|
||||
else {
|
||||
chrome.runtime.sendMessage(global.appId, msg);
|
||||
}
|
||||
}
|
||||
|
||||
check_complete_records(d) {
|
||||
/* '''Given a response d from a server,
|
||||
we want to know if its contents represents
|
||||
a complete set of records, however many.'''
|
||||
*/
|
||||
let complete_records = new Uint8Array();
|
||||
|
||||
while (d) {
|
||||
if (d.length < 5) {
|
||||
return {
|
||||
'is_complete': false,
|
||||
'comprecs': complete_records,
|
||||
'incomprecs': d
|
||||
};
|
||||
}
|
||||
var l = ba2int(d.slice(3, 5));
|
||||
if (d.length < (l + 5)) {
|
||||
return {
|
||||
'is_complete': false,
|
||||
'comprecs': complete_records,
|
||||
'incomprecs': d
|
||||
};
|
||||
} else if (d.length === (l + 5)) {
|
||||
return {
|
||||
'is_complete': true,
|
||||
'comprecs': concatTA(complete_records, d)
|
||||
};
|
||||
} else {
|
||||
complete_records = concatTA(complete_records, d.slice(0, l + 5));
|
||||
d = d.slice(l + 5);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (typeof module !== 'undefined'){ // we are in node.js environment
|
||||
module.exports={
|
||||
};
|
||||
}
|
||||
627
core/TLS.js
Normal file
627
core/TLS.js
Normal file
@@ -0,0 +1,627 @@
|
||||
import {TWOPC} from './twopc/TWOPC.js';
|
||||
import {global} from './globals.js';
|
||||
import {ba2str, b64decode, concatTA, int2ba, sha256, b64encode, str2ba, assert,
|
||||
ba2int, dechunk_http, gunzip_http, getRandom, sigDER2p1363, pubkeyPEM2raw, eq,
|
||||
xor, AESECBencrypt, buildChunkMetadata, b64urlencode} from './utils.js';
|
||||
import {verifyChain, checkCertSubjName} from './verifychain.js';
|
||||
import {Socket} from './Socket.js';
|
||||
|
||||
|
||||
export class TLS {
|
||||
// allHandshakes is a concatenation of all handshake messages up to this point.
|
||||
// This is only data visible at the handshake layer and does not include record layer headers
|
||||
allHandshakes;
|
||||
// certPath is an array of certificates from the server arranged by pkijs in the ascending
|
||||
// order from leaf to root
|
||||
certPath;
|
||||
// cke is TLS handshake's Client Key Exchange message
|
||||
cke;
|
||||
clientRandom;
|
||||
commPrivkey;
|
||||
commSymmetricKey;
|
||||
headers;
|
||||
isMhm; // multiple handshake messages
|
||||
mustVerifyCert;
|
||||
notaryWillEncryptRequest;
|
||||
options;
|
||||
port;
|
||||
rsaSig;
|
||||
serverRandom;
|
||||
sckt;
|
||||
serverEcPubkey;
|
||||
secret; // for debug purposes only
|
||||
// sid is id for this notarization session
|
||||
sid;
|
||||
serverName;
|
||||
useMaxFragmentLength;
|
||||
|
||||
constructor (serverName, port, headers, options){
|
||||
this.serverName = serverName;
|
||||
this.port = port;
|
||||
this.headers = headers;
|
||||
this.sid = Math.random().toString(36).slice(-10);
|
||||
this.options = options;
|
||||
this.useMaxFragmentLength = options.useMaxFragmentLength;
|
||||
this.notaryWillEncryptRequest = options.notaryWillEncryptRequest;
|
||||
this.mustVerifyCert = options.mustVerifyCert;
|
||||
this.sckt = new Socket(serverName, port);
|
||||
}
|
||||
|
||||
buildClientHello(){
|
||||
let tmp = [];
|
||||
tmp.push(0x00, 0x0a); // Type supported_groups
|
||||
tmp.push(0x00, 0x04); // Length
|
||||
tmp.push(0x00, 0x02); // Supported Groups List Length
|
||||
tmp.push(0x00, 0x17); // Supported Group: secp256r1
|
||||
const supported_groups_extension = new Uint8Array(tmp);
|
||||
|
||||
tmp = [];
|
||||
tmp.push(0x00, 0x0d); // Type signature_algorithms
|
||||
tmp.push(0x00, 0x04); // Length
|
||||
tmp.push(0x00, 0x02); // Signature Hash Algorithms Length
|
||||
tmp.push(0x04, 0x01); // Signature Algorithm: rsa_pkcs1_sha256 (0x0401)
|
||||
const signature_algorithm_extension = new Uint8Array(tmp);
|
||||
|
||||
tmp = [];
|
||||
const server_name = str2ba(this.serverName);
|
||||
tmp.push(0x00, 0x00); // Extension type: server_name
|
||||
tmp.push(...Array.from(int2ba(server_name.length+5, 2))); // Length
|
||||
tmp.push(...Array.from(int2ba(server_name.length+3, 2))); // Server Name List Length
|
||||
tmp.push(0x00); // Type: host name
|
||||
tmp.push(...Array.from(int2ba(server_name.length, 2))); // Server Name Length
|
||||
tmp.push(...Array.from(server_name));
|
||||
const server_name_extension = new Uint8Array(tmp);
|
||||
|
||||
tmp = [];
|
||||
if (this.useMaxFragmentLength){
|
||||
tmp.push(0x00, 0x01); // Type: max_fragment_length
|
||||
tmp.push(0x00, 0x01); // Length
|
||||
// allowed values 0x01 = 512 0x02 = 1024 0x03 = 2048 0x04 = 4096
|
||||
// some servers support 0x04 but send alert if < 0x04
|
||||
tmp.push(0x04);
|
||||
}
|
||||
const max_fragment_length_extension = new Uint8Array(tmp);
|
||||
|
||||
const extlen = supported_groups_extension.length + signature_algorithm_extension.length +
|
||||
server_name_extension.length + max_fragment_length_extension.length;
|
||||
|
||||
tmp = [];
|
||||
tmp.push(0x01); // Handshake type: Client Hello
|
||||
tmp.push(...int2ba(extlen + 43, 3) ); // Length
|
||||
tmp.push(0x03, 0x03); // Version: TLS 1.2
|
||||
this.clientRandom = getRandom(32);
|
||||
tmp.push(...Array.from(this.clientRandom));
|
||||
tmp.push(0x00); // Session ID Length
|
||||
tmp.push(0x00, 0x02); // Cipher Suites Length
|
||||
tmp.push(0xc0, 0x2f); // Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||
tmp.push(0x01); // Compression Methods Length
|
||||
tmp.push(0x00); // Compression Method: null
|
||||
tmp.push(...int2ba(extlen, 2));
|
||||
const ch = concatTA(
|
||||
new Uint8Array(tmp),
|
||||
supported_groups_extension,
|
||||
signature_algorithm_extension,
|
||||
server_name_extension,
|
||||
max_fragment_length_extension);
|
||||
|
||||
this.allHandshakes = ch;
|
||||
|
||||
tmp = [];
|
||||
tmp.push(0x16); // Type: Handshake
|
||||
tmp.push(0x03, 0x03); // Version: TLS 1.2
|
||||
tmp.push(...int2ba(ch.length, 2)); // Length
|
||||
const tls_record_header = new Uint8Array(tmp);
|
||||
|
||||
return concatTA(tls_record_header, ch);
|
||||
}
|
||||
|
||||
async verifyNotarySig(sigDER, pubKey, signed_data, options){
|
||||
const isRaw = (options == 'raw') ? true : false;
|
||||
const sig_p1363 = sigDER2p1363(sigDER);
|
||||
const notaryPubkey = isRaw ? pubKey : pubkeyPEM2raw(pubKey);
|
||||
|
||||
const pubkeyCryptoKey = await crypto.subtle.importKey(
|
||||
'raw', notaryPubkey.buffer, {name: 'ECDSA', namedCurve:'P-256'}, true, ['verify']);
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const result = await crypto.subtle.verify(
|
||||
{'name':'ECDSA', 'hash':'SHA-256'}, pubkeyCryptoKey, sig_p1363.buffer, signed_data.buffer);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
async parse_commpk_commpksig_cpk(dataEnc){
|
||||
// Notary's EC pubkey (to derive ECDH secret for communication) is not encrypted
|
||||
const comm_pk = dataEnc.slice(0,65);
|
||||
// for debug purposes only
|
||||
this.secret = dataEnc.slice(65,97);
|
||||
|
||||
this.commSymmetricKey = await getECDHSecret(comm_pk, this.commPrivkey);
|
||||
const data = await this.decryptFromNotary(
|
||||
this.commSymmetricKey,
|
||||
dataEnc.slice(65+this.secret.length));
|
||||
|
||||
let o = 0; // offset
|
||||
// get signature over communication pubkey
|
||||
const ssrvLen = ba2int(data.slice(o,o+=1));
|
||||
const signingServerRetval = data.slice(o, o+=ssrvLen);
|
||||
const cpk = data.slice(o,o+=65); // Client's pubkey for ECDH
|
||||
// parse signing server's return value
|
||||
o = 0;
|
||||
const sessionSigLen = ba2int(signingServerRetval.slice(o, o+=1));
|
||||
const sessionSig = signingServerRetval.slice(o, o+=sessionSigLen);
|
||||
const ephemKeySigLen = ba2int(signingServerRetval.slice(o, o+=1));
|
||||
const ephemKeySig = signingServerRetval.slice(o, o+=ephemKeySigLen);
|
||||
const ephemPubKey = signingServerRetval.slice(o, o+=65);
|
||||
const ephemValidFrom = signingServerRetval.slice(o, o+=4);
|
||||
const ephemValidUntil = signingServerRetval.slice(o, o+=4);
|
||||
|
||||
// check signature
|
||||
const to_be_signed = await sha256(comm_pk);
|
||||
assert(await this.verifyNotarySig(sessionSig, ephemPubKey, to_be_signed, 'raw') == true);
|
||||
// the ephemeral key with its validity time range is signed by master key
|
||||
const ephemTBS = await sha256(concatTA(ephemPubKey, ephemValidFrom, ephemValidUntil));
|
||||
assert(await this.verifyNotarySig(ephemKeySig, this.notary.pubkeyPEM, ephemTBS) == true);
|
||||
this.checkEphemKeyExpiration(ephemValidFrom, ephemValidUntil);
|
||||
return cpk;
|
||||
}
|
||||
|
||||
parseServerHello(s){
|
||||
let p = 0;
|
||||
assert(eq(s.slice(p, p+=1), [0x02])); // Server Hello
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const shlen = ba2int(s.slice(p, p+=3));
|
||||
assert(eq(s.slice(p, p+=2), [0x03, 0x03])); // Version: TLS 1.2
|
||||
this.serverRandom = s.slice(p, p+=32);
|
||||
const sidlen = ba2int(s.slice(p, p+=1));
|
||||
if (sidlen > 0){
|
||||
p+=sidlen; // 32 bytes of session ID, if any
|
||||
}
|
||||
assert(eq(s.slice(p, p+=2), [0xc0, 0x2f])); // Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||
assert(eq(s.slice(p, p+=1), [0x00])); // Compression Method: null (0)
|
||||
// May contain Extensions. We don't need to parse them
|
||||
}
|
||||
|
||||
async parseCertificate(s){
|
||||
let p = 0;
|
||||
assert(eq(s.slice(p, p+=1), [0x0b])); // Certificate
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const clen = ba2int(s.slice(p, p+=3));
|
||||
const certslen = ba2int(s.slice(p, p+=3));
|
||||
const certs_last_pos = p + certslen;
|
||||
const certs = [];
|
||||
while (p < certs_last_pos){
|
||||
const certlen = ba2int(s.slice(p, p+=3));
|
||||
const certder = s.slice(p, p+certlen);
|
||||
p+=certlen;
|
||||
certs.push(certder);
|
||||
}
|
||||
const vcrv = await verifyChain(certs);
|
||||
assert (vcrv.result == true);
|
||||
this.certPath = vcrv.certificatePath;
|
||||
assert(checkCertSubjName(this.certPath[0], this.serverName) == true);
|
||||
return p;
|
||||
}
|
||||
|
||||
async parseServerKeyExchange(s){
|
||||
let p = 0;
|
||||
assert(eq(s.slice(p, p+=1), [0x0c])); // Handshake Type: Server Key Exchange (12)
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const skelen = ba2int(s.slice(p, p+=3));
|
||||
// EC Diffie-Hellman Server Params
|
||||
assert(eq(s.slice(p, p+=1), [0x03])); // Curve Type: named_curve (0x03)
|
||||
assert(eq(s.slice(p, p+=2), [0x00, 0x17])); // Named Curve: secp256r1 (0x0017)
|
||||
const pklen = ba2int(s.slice(p, p+=1));
|
||||
assert (pklen == 65); // Pubkey Length: 65
|
||||
this.serverEcPubkey = s.slice(p, p+=pklen);
|
||||
assert(eq(s.slice(p, p+=2), [0x04, 0x01])); // #Signature Algorithm: rsa_pkcs1_sha256 (0x0401)
|
||||
const siglen = ba2int(s.slice(p, p+=2));
|
||||
this.rsaSig = s.slice(p, p+=siglen);
|
||||
|
||||
const result = await TLS.verifyECParamsSig(this.certPath[0], this.serverEcPubkey, this.rsaSig, this.clientRandom, this.serverRandom);
|
||||
assert (result == true);
|
||||
return p;
|
||||
}
|
||||
|
||||
// Obsolete: encrypt request without 2PC.
|
||||
async encryptRequest(headers_str, client_write_key, client_write_IV, chunkSize){
|
||||
let headers = str2ba(headers_str);
|
||||
chunkSize = chunkSize || headers.length; // one chunk only
|
||||
const chunks = Math.ceil(headers.length/chunkSize);
|
||||
const encReq = [];
|
||||
for (let i=0; i < chunks; i++){
|
||||
let thisChunkSize = chunkSize;
|
||||
if (i == chunks-1){
|
||||
// last chunk may be smaller
|
||||
const rem = headers.length % chunkSize;
|
||||
thisChunkSize = (rem == 0) ? chunkSize : rem;
|
||||
}
|
||||
const explicit_nonce = int2ba(2+i, 8);
|
||||
// const explicit_nonce = getRandom(8)
|
||||
const nonce = concatTA(client_write_IV, explicit_nonce);
|
||||
const seq_num = 1+i;
|
||||
const aad = concatTA(
|
||||
int2ba(seq_num, 8),
|
||||
new Uint8Array([0x17, 0x03, 0x03]), // type 0x17 = Application data , TLS Version 1.2
|
||||
int2ba(thisChunkSize, 2)); // unencrypted data length in bytes
|
||||
const cwkCryptoKey = await crypto.subtle.importKey(
|
||||
'raw',
|
||||
client_write_key.buffer,
|
||||
'AES-GCM',
|
||||
true,
|
||||
['encrypt', 'decrypt']);
|
||||
const ciphertext = await crypto.subtle.encrypt({
|
||||
name: 'AES-GCM',
|
||||
iv: nonce.buffer,
|
||||
additionalData: aad.buffer},
|
||||
cwkCryptoKey,
|
||||
headers.slice(chunkSize*i, chunkSize*(i+1)).buffer);
|
||||
encReq.push(concatTA(explicit_nonce, new Uint8Array(ciphertext)));
|
||||
}
|
||||
return encReq;
|
||||
}
|
||||
|
||||
// ephemeral key usage time must be within the time of ephemeral key validity
|
||||
checkEphemKeyExpiration(validFrom, validUntil, time){
|
||||
time = time || Math.floor(new Date().getTime() / 1000);
|
||||
if (ba2int(validFrom) > time || time > ba2int(validUntil)){
|
||||
throw('Ephemeral key expired');
|
||||
}
|
||||
}
|
||||
|
||||
async buildAndSendClientHello(){
|
||||
const ch = this.buildClientHello();
|
||||
await this.sckt.connect();
|
||||
this.sckt.send(ch); // Send Client Hello
|
||||
}
|
||||
|
||||
// receiveAndParseServerHelloAndFriends receives Server Hello, Certificate,
|
||||
// Server Key Exchange, and Server Hello Done and parses them
|
||||
async receiveAndParseServerHello(){
|
||||
try{
|
||||
this.sckt.recv_timeout = 5 * 1000;
|
||||
var s = await this.sckt.recv(true);
|
||||
} catch (err){
|
||||
await this.sckt.close();
|
||||
// some incompatible websites silently do not respond to ClientHello
|
||||
throw('Failed to receive a response from a webserver. Make sure your internet connection is working and try again. If this error persists, this may mean that the webserver is not compatible with PageSigner. Please contact the PageSigner devs about this issue.');
|
||||
}
|
||||
// restore normal timeout value
|
||||
this.sckt.recv_timeout = 20 * 1000;
|
||||
|
||||
// Parse Server Hello, Certificate, Server Key Exchange, Server Hello Done
|
||||
if (eq(s.slice(0,2), [0x15, 0x03])){
|
||||
console.log('Server sent Alert instead of Server Hello');
|
||||
throw ('Unfortunately PageSigner is not yet able to notarize this website. Please contact the PageSigner devs about this issue.');
|
||||
}
|
||||
let p = 0; // current position in the byte stream
|
||||
assert(eq(s.slice(p, p+=1), [0x16])); // Type: Handshake
|
||||
assert(eq(s.slice(p, p+=2), [0x03, 0x03])); // Version: TLS 1.2
|
||||
const handshakelen = ba2int(s.slice(p, p+=2));
|
||||
// This may be the length of multiple handshake messages (MHM)
|
||||
// For MHM there is only 1 TLS Record layer header followed by Handshake layer messages
|
||||
// Without MHM, each handshake message has its own TLS Record header
|
||||
|
||||
// Parse Server Hello
|
||||
const shlen = ba2int(s.slice(p+1, p+4));
|
||||
const sh = s.slice(p, p + 4 + shlen);
|
||||
this.updateAllHandshakes(sh);
|
||||
this.parseServerHello(sh);
|
||||
p = 5+4+shlen;
|
||||
|
||||
if (handshakelen > shlen+4) {
|
||||
this.isMhm = true; }// multiple handshake messages
|
||||
let reclenMhm = 0;
|
||||
if (!this.isMhm){
|
||||
// read the TLS Record header
|
||||
assert(eq(s.slice(p, p+=3), [0x16, 0x03, 0x03])); // Type: Handshake # Version: TLS 1.2
|
||||
reclenMhm = ba2int(s.slice(p, p+=2));
|
||||
}
|
||||
|
||||
// Parse Certificate
|
||||
const clen = ba2int(s.slice(p+1, p+4));
|
||||
if (!this.isMhm) {
|
||||
assert(reclenMhm == clen+4);}
|
||||
const c = s.slice(p, p + 4 + clen);
|
||||
this.allHandshakes = concatTA(this.allHandshakes, c);
|
||||
const cParsedByted = await this.parseCertificate(c);
|
||||
p += cParsedByted;
|
||||
|
||||
if (this.isMhm && (handshakelen+5 == p)){
|
||||
// another MHM header will follow, read its header
|
||||
assert(eq(s.slice(p, p+=1), [0x16])); // Type: Handshake
|
||||
assert(eq(s.slice(p, p+=2), [0x03, 0x03])); // Version: TLS 1.2
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const handshakelen = ba2int(s.slice(p, p+=2)); // This may be the length of multiple handshake messages (MHM)
|
||||
}
|
||||
reclenMhm = 0;
|
||||
if (!this.isMhm){
|
||||
// read the TLS Record header
|
||||
assert(eq(s.slice(p, p+=3), [0x16, 0x03, 0x03])); // Type: Handshake # Version: TLS 1.2
|
||||
reclenMhm = ba2int(s.slice(p, p+=2));
|
||||
}
|
||||
|
||||
// Parse Server Key Exchange
|
||||
const skelen = ba2int(s.slice(p+1, p+4));
|
||||
if (!this.isMhm){
|
||||
assert(reclenMhm == skelen+4);}
|
||||
const ske = s.slice(p, p + 4+ skelen);
|
||||
this.allHandshakes = concatTA(this.allHandshakes, ske);
|
||||
const skeParsedByted = await this.parseServerKeyExchange(ske);
|
||||
p += skeParsedByted;
|
||||
|
||||
// Parse Server Hello Done
|
||||
if (!this.isMhm) {
|
||||
// read the TLS Record header
|
||||
assert(eq(s.slice(p, p+=3), [0x16, 0x03, 0x03])); // Type: Handshake # Version: TLS 1.2
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const reclen = ba2int(s.slice(p, p+=2));
|
||||
}
|
||||
const shd = s.slice(p, p+=4);
|
||||
assert(eq(shd, [0x0e, 0x00, 0x00, 0x00]));
|
||||
assert(p == s.length);
|
||||
this.updateAllHandshakes(shd);
|
||||
return this.serverEcPubkey;
|
||||
}
|
||||
|
||||
// buildClientKeyExchange builds the TLS handshake's Client Key Exchange message
|
||||
// cpubBytes is client's pubkey for the ECDH
|
||||
async buildClientKeyExchange(cpubBytes){
|
||||
let tmp = [0x10]; // Handshake type: Client Key Exchange
|
||||
tmp.push(0x00, 0x00, 0x42); // Length
|
||||
tmp.push(0x41); // Pubkey Length: 65
|
||||
// 0x04 means compressed pubkey format
|
||||
this.cke = concatTA(new Uint8Array(tmp), new Uint8Array([0x04]), cpubBytes);
|
||||
this.updateAllHandshakes(this.cke);
|
||||
}
|
||||
|
||||
getRandoms(){
|
||||
return [this.clientRandom, this.serverRandom];
|
||||
}
|
||||
|
||||
getAllHandshakes(){
|
||||
return this.allHandshakes;
|
||||
}
|
||||
|
||||
getCertPath(){
|
||||
return this.certPath;
|
||||
}
|
||||
|
||||
getRSAsignature(){
|
||||
return this.rsaSig;
|
||||
}
|
||||
|
||||
// sendClientFinished accepts encrypted Client Finished (CF), auth tag for CF, verify_data for CF.
|
||||
// It then sends Client Key Exchange, Change Cipher Spec and encrypted Client Finished
|
||||
async sendClientFinished(encCF, tagCF){
|
||||
const cke_tls_record_header = new Uint8Array([0x16, 0x03, 0x03, 0x00, 0x46]); // Type: Handshake, Version: TLS 1.2, Length
|
||||
const ccs = new Uint8Array([0x14, 0x03, 0x03, 0x00, 0x01, 0x01]);
|
||||
const client_finished = concatTA(int2ba(1, 8), encCF, tagCF);
|
||||
// Finished message of 40 (0x28) bytes length
|
||||
const data_to_send = concatTA(cke_tls_record_header, this.cke, ccs,
|
||||
new Uint8Array([0x16, 0x03, 0x03, 0x00, 0x28]), client_finished);
|
||||
this.sckt.send(data_to_send);
|
||||
}
|
||||
|
||||
updateAllHandshakes(appendMsg){
|
||||
this.allHandshakes = concatTA(this.allHandshakes, appendMsg);
|
||||
}
|
||||
|
||||
// receiveServerFinished receives Change Cipher Spec and encrypted Server Finished.
|
||||
// Returns encrypted Server Finished
|
||||
async receiveServerFinished(){
|
||||
const data = await this.sckt.recv(true);
|
||||
|
||||
if (eq(data.slice(0,2), [0x15, 0x03])){
|
||||
console.log('Server sent Alert instead of Server Finished');
|
||||
throw('Server sent Alert instead of Server Finished');
|
||||
}
|
||||
// Parse CCS and Server's Finished
|
||||
const ccs_server = data.slice(0,6);
|
||||
assert(eq(ccs_server, [0x14, 0x03, 0x03, 0x00, 0x01, 0x01]));
|
||||
|
||||
let f = null; // server finished
|
||||
if (data.length === 6) {
|
||||
// didnt receive the Server Finished, try again
|
||||
f = await this.sckt.recv(true);
|
||||
}
|
||||
else {
|
||||
f = data.slice(6);
|
||||
}
|
||||
|
||||
assert (eq(f.slice(0,5), [0x16, 0x03, 0x03, 0x00, 0x28]));
|
||||
const encSF = f.slice(5, 45); // encrypted Server Finished
|
||||
// There may be some extra data received after the Server Finished. We ignore it.
|
||||
return encSF;
|
||||
}
|
||||
|
||||
async buildAndSendRequest(gctrBlocks, ghashOutputs, encRequestBlocks){
|
||||
// authTags contains authentication tag for each TLS record in the request
|
||||
// (For now there's a limit of 1 TLS record for the client request)
|
||||
const authTags = [];
|
||||
assert(ghashOutputs.length === gctrBlocks.length);
|
||||
for (let i=0; i < ghashOutputs.length; i++){
|
||||
authTags[i] = xor(ghashOutputs[i], gctrBlocks[i]);
|
||||
}
|
||||
|
||||
const finalRecords = [];
|
||||
const TLSRecord = concatTA(int2ba(2, 8), ...encRequestBlocks, authTags[0]);
|
||||
finalRecords.push(TLSRecord);
|
||||
|
||||
let appdata = new Uint8Array();
|
||||
for (let i=0; i< finalRecords.length; i++){
|
||||
appdata = concatTA(
|
||||
appdata,
|
||||
new Uint8Array([0x17, 0x03, 0x03]), // Type: Application data, TLS Version 1.2
|
||||
int2ba(finalRecords[i].length, 2), // 2-byte length of encrypted data
|
||||
finalRecords[i]);
|
||||
}
|
||||
console.log('sending http request');
|
||||
this.sckt.send(appdata);
|
||||
}
|
||||
|
||||
// receiveServerResponse returns encrypted server response split into TLS records
|
||||
async receiveServerResponse(){
|
||||
const server_response = await this.sckt.recv();
|
||||
this.sckt.close();
|
||||
console.log('server_response.length', server_response.length);
|
||||
const encRecords = this.splitResponseIntoRecords(server_response);
|
||||
return encRecords;
|
||||
}
|
||||
|
||||
// Not in use now, will be used for the selective hiding in the future
|
||||
async hashesOfAllCounterBlocks(server_write_key, server_write_IV, encRecords){
|
||||
// calculate hashes of every counter
|
||||
var encCounters = []; // encrypted counters for each TLS recorsd
|
||||
var hashesOfEncCounters = []; // hash of each AES block
|
||||
|
||||
for (var i=0; i<encRecords.length; i++){
|
||||
var rec = encRecords[i];
|
||||
var numberOfBlocks = Math.ceil((rec.length-8-16) / 16);
|
||||
var nonce = rec.slice(0,8);
|
||||
var hashesOfEncCountersInRecord = [];
|
||||
var encCountersInRecord = [];
|
||||
for (var j=0; j<numberOfBlocks; j++){
|
||||
var count_ba = int2ba(j+2, 4); // block counter starts with 2
|
||||
var counter = concatTA(server_write_IV, nonce, count_ba);
|
||||
let counter_enc = AESECBencrypt(server_write_key, counter);
|
||||
var hashOfEncCounter = await sha256(counter_enc);
|
||||
hashesOfEncCountersInRecord.push(hashOfEncCounter);
|
||||
encCountersInRecord.push(counter_enc);
|
||||
}
|
||||
hashesOfEncCounters.push(concatTA(...hashesOfEncCountersInRecord));
|
||||
encCountersInRecord = [].concat.apply([], encCountersInRecord); // flatten
|
||||
encCounters.push(encCountersInRecord);
|
||||
|
||||
// flatten the array and hash it
|
||||
return await sha256([].concat.apply([], hashesOfEncCounters));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// split a raw TLS response into encrypted application layer records
|
||||
splitResponseIntoRecords(s){
|
||||
var records = [];
|
||||
var p = 0; // position in the stream
|
||||
|
||||
while (p < s.length){
|
||||
if (! eq(s.slice(p,p+3), [0x17,0x03,0x03])){
|
||||
if (eq(s.slice(p,p+3), [0x15,0x03,0x03])){
|
||||
// if the alert is not the first record, then it is most likely a
|
||||
// close_notify
|
||||
if (records.length == 0){
|
||||
console.log('Server sent Alert instead of response');
|
||||
throw('Server sent Alert instead of response');
|
||||
}
|
||||
}
|
||||
else{
|
||||
console.log('Server sent an unknown message');
|
||||
throw('Server sent an unknown message');
|
||||
}
|
||||
}
|
||||
|
||||
p+=3;
|
||||
let reclen = ba2int(s.slice(p, p+=2));
|
||||
let record = s.slice(p, p+=reclen);
|
||||
records.push(record);
|
||||
}
|
||||
assert(p == s.length, 'The server sent a misformatted reponse');
|
||||
return records;
|
||||
}
|
||||
|
||||
// verify signature over EC parameters from Server Key Exchange
|
||||
static async verifyECParamsSig(cert, ECpubkey, sig, cr, sr){
|
||||
const modulus = new Uint8Array(cert.subjectPublicKeyInfo.parsedKey.modulus.valueBlock.valueHex);
|
||||
// JSON web key format for public key with exponent 65537
|
||||
const jwk = {'kty':'RSA', 'use':'sig', 'e': 'AQAB', 'n': b64urlencode(modulus)};
|
||||
|
||||
// 4 bytes of EC Diffie-Hellman Server Params + pubkey
|
||||
const to_be_signed = concatTA(cr, sr, new Uint8Array([0x03, 0x00, 0x17, 0x41]), ECpubkey);
|
||||
const rsa_pubkey = await crypto.subtle.importKey(
|
||||
'jwk',
|
||||
jwk,
|
||||
{name: 'RSASSA-PKCS1-v1_5', hash:'SHA-256'},
|
||||
true, ['verify']);
|
||||
try {
|
||||
var result = await crypto.subtle.verify('RSASSA-PKCS1-v1_5', rsa_pubkey, sig.buffer, to_be_signed.buffer);
|
||||
} catch (e) {
|
||||
console.log('EC parameters signature verification failed');
|
||||
console.log(e, e.name);
|
||||
throw('EC parameters signature verification failed');
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export async function decrypt_tls_responseV6(encRecords, key, IV){
|
||||
const cryptoKey = await crypto.subtle.importKey(
|
||||
'raw', key.buffer, 'AES-GCM', true, ['decrypt']);
|
||||
|
||||
let seq_num = 0; // seq_num 0 was in the Server Finished message, we will start with seq_num 1
|
||||
const plaintext = [];
|
||||
for (let i=0; i < encRecords.length; i++){
|
||||
const rec = encRecords[i];
|
||||
if (i === encRecords.length-1 && rec.length === 26){
|
||||
// this is close_notify which we don't include in the output
|
||||
continue;
|
||||
}
|
||||
let tmp = [];
|
||||
seq_num += 1;
|
||||
tmp.push(...int2ba(seq_num, 8));
|
||||
tmp.push(...[0x17,0x03,0x03]); // type 0x17 = Application Data, TLS Version 1.2
|
||||
// len(unencrypted data) == len (encrypted data) - len(explicit nonce) - len (auth tag)
|
||||
tmp.push(...int2ba(rec.length - 8 - 16, 2));
|
||||
const aad = new Uint8Array(tmp);// additional authenticated data
|
||||
const nonce = concatTA(IV, rec.slice(0,8));
|
||||
plaintext.push( new Uint8Array (await crypto.subtle.decrypt(
|
||||
{name: 'AES-GCM', iv: nonce.buffer, additionalData: aad.buffer},
|
||||
cryptoKey,
|
||||
rec.slice(8).buffer)));
|
||||
}
|
||||
return plaintext;
|
||||
}
|
||||
|
||||
export async function getExpandedKeys(preMasterSecret, cr, sr){
|
||||
const Secret_CryptoKey = await crypto.subtle.importKey(
|
||||
'raw',
|
||||
preMasterSecret.buffer,
|
||||
{name: 'HMAC', hash:'SHA-256'},
|
||||
true,
|
||||
['sign']);
|
||||
|
||||
// calculate Master Secret and expanded keys
|
||||
const seed = concatTA(str2ba('master secret'), cr, sr);
|
||||
const a0 = seed;
|
||||
const a1 = new Uint8Array (await crypto.subtle.sign('HMAC', Secret_CryptoKey, a0.buffer));
|
||||
const a2 = new Uint8Array (await crypto.subtle.sign('HMAC', Secret_CryptoKey, a1.buffer));
|
||||
const p1 = new Uint8Array (await crypto.subtle.sign('HMAC', Secret_CryptoKey, concatTA(a1,seed).buffer));
|
||||
const p2 = new Uint8Array (await crypto.subtle.sign('HMAC', Secret_CryptoKey, concatTA(a2,seed).buffer));
|
||||
const ms = concatTA(p1, p2).slice(0,48);
|
||||
const MS_CryptoKey = await crypto.subtle.importKey('raw', ms.buffer, {name: 'HMAC', hash:'SHA-256'}, true, ['sign']);
|
||||
|
||||
// Expand keys
|
||||
const eseed = concatTA(str2ba('key expansion'), sr, cr);
|
||||
const ea0 = eseed;
|
||||
const ea1 = new Uint8Array (await crypto.subtle.sign('HMAC', MS_CryptoKey, ea0.buffer));
|
||||
const ea2 = new Uint8Array (await crypto.subtle.sign('HMAC', MS_CryptoKey, ea1.buffer));
|
||||
const ep1 = new Uint8Array (await crypto.subtle.sign('HMAC', MS_CryptoKey, concatTA(ea1,eseed).buffer));
|
||||
const ep2 = new Uint8Array (await crypto.subtle.sign('HMAC', MS_CryptoKey, concatTA(ea2,eseed).buffer));
|
||||
|
||||
const ek = concatTA(ep1, ep2).slice(0,40);
|
||||
// GCM doesnt need MAC keys
|
||||
const client_write_key = ek.slice(0, 16);
|
||||
const server_write_key = ek.slice(16, 32);
|
||||
const client_write_IV = ek.slice(32, 36);
|
||||
const server_write_IV = ek.slice(36, 40);
|
||||
return [client_write_key, server_write_key, client_write_IV, server_write_IV, MS_CryptoKey];
|
||||
}
|
||||
|
||||
|
||||
if (typeof module !== 'undefined'){ // we are in node.js environment
|
||||
module.exports={
|
||||
computeCommitHash,
|
||||
decrypt_tls_responseV5,
|
||||
start_audit,
|
||||
getExpandedKeys
|
||||
};
|
||||
}
|
||||
145
core/TLSNotarySession.js
Normal file
145
core/TLSNotarySession.js
Normal file
@@ -0,0 +1,145 @@
|
||||
import {TWOPC} from './twopc/TWOPC.js';
|
||||
import {TLS} from './TLS.js';
|
||||
import {concatTA, sha256, assert, eq, xor, str2ba, pubkeyPEM2raw} from './utils.js';
|
||||
|
||||
|
||||
// class TLSNotarySession impements one notarization session
|
||||
// (one client request followed by one server response) using the TLSNotary protocol.
|
||||
export class TLSNotarySession{
|
||||
// twopc is an instance of class TWOPC. Used to speak to the notary.
|
||||
twopc;
|
||||
// tls is an instance of class TLS. Used to speak to the webserver.
|
||||
tls;
|
||||
// probeTLS is used to probe the webserver to see if it supports TLSNotary,
|
||||
// before we start any time-intensive 2PC
|
||||
probeTLS;
|
||||
options;
|
||||
request;
|
||||
notary;
|
||||
pm;
|
||||
constructor(server, port, request, notary, sessionOptions, circuits, progressMonitor){
|
||||
this.twopc = new TWOPC(notary, request.length, circuits, progressMonitor);
|
||||
this.tls = new TLS(server, port, request, sessionOptions);
|
||||
this.probeTLS = new TLS(server, port, request, sessionOptions);
|
||||
this.request = str2ba(request);
|
||||
this.notary = notary;
|
||||
this.pm = progressMonitor;
|
||||
}
|
||||
|
||||
async start(){
|
||||
await this.probeTLS.buildAndSendClientHello();
|
||||
await this.probeTLS.receiveAndParseServerHello();
|
||||
await this.probeTLS.sckt.close();
|
||||
await this.twopc.preCompute();
|
||||
await this.tls.buildAndSendClientHello();
|
||||
const serverEcPubkey = await this.tls.receiveAndParseServerHello();
|
||||
const serverX = serverEcPubkey.slice(1,33);
|
||||
const serverY = serverEcPubkey.slice(33,65);
|
||||
this.pm.update('last_stage', {'current': 3, 'total': 10});
|
||||
const [pmsShare, cpubBytes] = await this.twopc.getECDHShare(serverX, serverY);
|
||||
this.pm.update('last_stage', {'current': 4, 'total': 10});
|
||||
|
||||
await this.tls.buildClientKeyExchange(cpubBytes);
|
||||
const [cr, sr] = await this.tls.getRandoms();
|
||||
const [encCF, tagCF, vdCF] = await this.twopc.run(cr, sr, this.tls.getAllHandshakes(), pmsShare);
|
||||
// Finished (0x14) with length 12 (0x0c)
|
||||
this.tls.updateAllHandshakes(concatTA(new Uint8Array([0x14, 0x00, 0x00, 0x0c]), vdCF));
|
||||
await this.tls.sendClientFinished(encCF, tagCF);
|
||||
const encSF = await this.tls.receiveServerFinished();
|
||||
await this.twopc.checkServerFinished(encSF, this.tls.getAllHandshakes());
|
||||
this.pm.update('last_stage', {'current': 5, 'total': 10});
|
||||
|
||||
const encCountersForRequest = await this.twopc.getEncryptedCounters();
|
||||
this.pm.update('last_stage', {'current': 9, 'total': 10});
|
||||
const encRequestBlocks = this.encryptRequest(this.request, encCountersForRequest);
|
||||
const gctrBlocks = await this.twopc.getGctrBlocks();
|
||||
this.pm.update('last_stage', {'current': 10, 'total': 10});
|
||||
const [ghashOutputs, ghashInputsBlob] = await this.twopc.getTagFromPowersOfH(encRequestBlocks);
|
||||
await this.tls.buildAndSendRequest(gctrBlocks, ghashOutputs, encRequestBlocks);
|
||||
const serverRecords = await this.tls.receiveServerResponse();
|
||||
await this.tls.sckt.close();
|
||||
|
||||
const commitHash = await TLSNotarySession.computeCommitHash(serverRecords);
|
||||
const [cwkShare, civShare, swkShare, sivShare] = this.twopc.getKeyShares();
|
||||
const keyShareHash = await sha256(concatTA(cwkShare, civShare, swkShare, sivShare));
|
||||
const pmsShareHash = await sha256(pmsShare);
|
||||
const data5 = await this.twopc.send('commitHash', concatTA(
|
||||
commitHash,
|
||||
keyShareHash,
|
||||
pmsShareHash));
|
||||
this.twopc.destroy();
|
||||
|
||||
let o = 0; // offset
|
||||
const signature = data5.slice(o, o+=64);
|
||||
const notaryPMSShare = data5.slice(o, o+=32);
|
||||
const notaryCwkShare = data5.slice(o, o+=16);
|
||||
const notaryCivShare = data5.slice(o, o+=4);
|
||||
const notarySwkShare = data5.slice(o, o+=16);
|
||||
const notarySivShare = data5.slice(o, o+=4);
|
||||
const timeBytes = data5.slice(o, o+=8);
|
||||
assert(data5.length == o);
|
||||
|
||||
const [eKey, eValidFrom, eValidUntil, eSigByMasterKey] = this.twopc.getEphemeralKey();
|
||||
|
||||
// convert certPath to DER.
|
||||
const certPath = this.tls.getCertPath();
|
||||
var certs = [];
|
||||
for (let cert of certPath){
|
||||
certs.push(new Uint8Array(cert.toSchema(true).toBER(false)));
|
||||
}
|
||||
|
||||
return {
|
||||
'certificates': certs,
|
||||
'notarization time': timeBytes,
|
||||
'server RSA sig': this.tls.getRSAsignature(),
|
||||
'server pubkey for ECDHE': serverEcPubkey,
|
||||
'notary PMS share': notaryPMSShare,
|
||||
'client PMS share': pmsShare,
|
||||
'client random': cr,
|
||||
'server random': sr,
|
||||
'notary client_write_key share': notaryCwkShare,
|
||||
'notary client_write_iv share': notaryCivShare,
|
||||
'notary server_write_key share': notarySwkShare,
|
||||
'notary server_write_iv share': notarySivShare,
|
||||
'client client_write_key share': cwkShare,
|
||||
'client client_write_iv share': civShare,
|
||||
'client server_write_key share': swkShare,
|
||||
'client server_write_iv share': sivShare,
|
||||
'client request ciphertext': ghashInputsBlob,
|
||||
'server response records': serverRecords,
|
||||
'session signature': signature,
|
||||
'ephemeral pubkey': eKey,
|
||||
'ephemeral valid from': eValidFrom,
|
||||
'ephemeral valid until': eValidUntil,
|
||||
'ephemeral signed by master key': eSigByMasterKey,
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
// encryptRequest encrypts (i.e. XORs) the plaintext request with encrypted counter blocks.
|
||||
// (This is how AES-GCM encryption works - first counter blocks are AES-ECB-encrypted,
|
||||
// then encrypted counter blocks are XORes with the plaintext to get the ciphertext.)
|
||||
encryptRequest(request, encCounterBlocks){
|
||||
assert(Math.ceil(request.length/16) === encCounterBlocks.length);
|
||||
const encRequestBlocks = [];
|
||||
for (let i=0; i < encCounterBlocks.length; i++){
|
||||
if (i == encCounterBlocks.length-1){
|
||||
// last block, make sure arrays are of the same length before xoring
|
||||
let lastBlockLen = this.request.length - i*16;
|
||||
encRequestBlocks.push(xor(encCounterBlocks[i].slice(0,lastBlockLen), this.request.slice(i*16)));
|
||||
}
|
||||
else {
|
||||
encRequestBlocks.push(xor(encCounterBlocks[i], this.request.slice(i*16, i*16+16)));
|
||||
}
|
||||
}
|
||||
return encRequestBlocks;
|
||||
}
|
||||
|
||||
|
||||
// computeCommitHash computes a hash over all TLS records with MACs
|
||||
static async computeCommitHash(encRecords){
|
||||
return await sha256(concatTA(...encRecords));
|
||||
}
|
||||
}
|
||||
|
||||
30
core/globals.js
Normal file
30
core/globals.js
Normal file
@@ -0,0 +1,30 @@
|
||||
export const global = {
|
||||
// defaultNotaryIP/Port is the default IP address/port of the notary server.
|
||||
// If this IP address becomes unavailable, Pagesigner will query backupUrl for
|
||||
// a new notary's IP address and will save the new IP address in the preferences.
|
||||
// defaultNotaryIP: '127.0.0.1',
|
||||
defaultNotaryIP: '3.235.172.232',
|
||||
defaultNotaryPort: 10011,
|
||||
// backupUrl is the URL to query to get the IP address of another notary
|
||||
// server in case if defaultNotaryIP is unreachable
|
||||
backupUrl: 'https://tlsnotary.org/backup_oracle',
|
||||
// use python for raw socket communication
|
||||
usePythonBackend: false,
|
||||
sessionOptions: {
|
||||
// Future use: use max_fragment_length TLS extension
|
||||
'useMaxFragmentLength': false,
|
||||
// can be set to false during debugging to be able to work with self-signed certs
|
||||
'mustVerifyCert': true
|
||||
},
|
||||
// if useHTTP11 is set to true then we use HTTP/1.1 in the request, otherwise
|
||||
// we use HTTP/1.0. Using HTTP/1.0 is the only way to prevent a webserver from using
|
||||
// chunked transfer encoding. This may be useful e.g. when webserver response is used
|
||||
// inside zk proofs and we want simpler parsing without de-chunking.
|
||||
useHTTP11: true,
|
||||
// appId is Chrome-only: the id of Chrome app used to send raw TCP packets.
|
||||
appId: 'oclohfdjoojomkfddjclanpogcnjhemd',
|
||||
// if useNotaryNoSandbox is set to true, then we fetch notary's pubkey by
|
||||
// querying /getPubKey and trust it. This is only useful when notary runs
|
||||
// in a non-sandbox environment.
|
||||
useNotaryNoSandbox: false
|
||||
};
|
||||
319
core/indexeddb.js
Normal file
319
core/indexeddb.js
Normal file
@@ -0,0 +1,319 @@
|
||||
let db;
|
||||
let db_blobs;
|
||||
|
||||
export async function init_db() {
|
||||
await new Promise(function(resolve, reject) {
|
||||
|
||||
const dbReq = indexedDB.open('PageSigner', 1);
|
||||
dbReq.onupgradeneeded = function (event) {
|
||||
// Set the db variable to our database so we can use it!
|
||||
db = event.target.result;
|
||||
|
||||
if (!db.objectStoreNames.contains('sessions')) {
|
||||
db.createObjectStore('sessions', { keyPath: 'creationTime', autoIncrement: true });
|
||||
}
|
||||
if (!db.objectStoreNames.contains('preferences')) {
|
||||
const preferences = db.createObjectStore('preferences', { keyPath: 'name', autoIncrement: true });
|
||||
preferences.add({name:'testing', value:false});
|
||||
preferences.add({name:'verbose', value:true});
|
||||
preferences.add({name:'firstTimeInitCompleted', value:false});
|
||||
preferences.add({name:'parsedCircuits', value:{}});
|
||||
preferences.add({name:'trustedOracle', value:{}});
|
||||
}
|
||||
};
|
||||
dbReq.onsuccess = function (event) {
|
||||
db = event.target.result;
|
||||
resolve();
|
||||
};
|
||||
dbReq.onerror = function (event) {
|
||||
alert('error opening database ' + event.target.errorCode);
|
||||
};
|
||||
});
|
||||
|
||||
await new Promise(function(resolve, reject) {
|
||||
|
||||
// We must create a separate DB for blobs. Having a separate store is not a solution because
|
||||
// i/o operations a very slow when there's blobs in a db
|
||||
const dbReq2 = indexedDB.open('PageSigner_blobs', 1);
|
||||
dbReq2.onupgradeneeded = function (event) {
|
||||
// Set the db variable to our database so we can use it!
|
||||
db_blobs = event.target.result;
|
||||
if (!db_blobs.objectStoreNames.contains('sessions')) {
|
||||
db_blobs.createObjectStore('sessions', { keyPath: 'creationTime', autoIncrement: true });
|
||||
}
|
||||
};
|
||||
dbReq2.onsuccess = function (event) {
|
||||
db_blobs = event.target.result;
|
||||
resolve();
|
||||
};
|
||||
dbReq2.onerror = function (event) {
|
||||
alert('error opening database ' + event.target.errorCode);
|
||||
};
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export async function addNewPreference(key, value){
|
||||
// check if the preference already exists
|
||||
const allPreferences = await new Promise(function(resolve, reject) {
|
||||
|
||||
const tx = db.transaction(['preferences'], 'readonly');
|
||||
const store = tx.objectStore('preferences');
|
||||
const req = store.getAll();
|
||||
|
||||
req.onsuccess = function(event) {
|
||||
// The result of req.onsuccess is an array
|
||||
resolve(event.target.result);
|
||||
};
|
||||
req.onerror = function(event) {
|
||||
alert('error in cursor request ' + event.target.errorCode);
|
||||
reject('error in cursor request ' + event.target.errorCode);
|
||||
};
|
||||
});
|
||||
|
||||
for (let pref of allPreferences){
|
||||
if (pref['name'] == key){
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// preference does not exist, add it
|
||||
await new Promise(function(resolve, reject) {
|
||||
const tx = db.transaction(['preferences'], 'readwrite');
|
||||
const store = tx.objectStore('preferences');
|
||||
store.add({name:key, value:value});
|
||||
tx.oncomplete = function() {
|
||||
resolve();
|
||||
};
|
||||
tx.onerror = function(event) {
|
||||
alert('error storing ' + event.target.errorCode);
|
||||
reject();
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export async function deleteSession(session) {
|
||||
await new Promise(function(resolve, reject) {
|
||||
const tx = db.transaction(['sessions'], 'readwrite');
|
||||
const sessions = tx.objectStore('sessions');
|
||||
const req = sessions.delete(session);
|
||||
req.onsuccess = function(event) {
|
||||
resolve();
|
||||
};
|
||||
});
|
||||
await new Promise(function(resolve, reject) {
|
||||
const tx = db_blobs.transaction(['sessions'], 'readwrite');
|
||||
const sessions = tx.objectStore('sessions');
|
||||
const req = sessions.delete(session);
|
||||
req.onsuccess = function(event) {
|
||||
resolve();
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export async function getAllSessions() {
|
||||
return await new Promise(function(resolve, reject) {
|
||||
|
||||
console.log('begin db');
|
||||
const tx = db.transaction(['sessions'], 'readonly');
|
||||
const store = tx.objectStore('sessions');
|
||||
const req = store.getAll();
|
||||
|
||||
req.onsuccess = function(event) {
|
||||
// The result of req.onsuccess is an array
|
||||
resolve(event.target.result);
|
||||
console.log('end db');
|
||||
};
|
||||
req.onerror = function(event) {
|
||||
alert('error in cursor request ' + event.target.errorCode);
|
||||
reject('error in cursor request ' + event.target.errorCode);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
export async function saveNewSession(date, host, request, response, pgsg, options){
|
||||
await new Promise(function(resolve, reject) {
|
||||
const tx = db.transaction(['sessions'], 'readwrite');
|
||||
const store = tx.objectStore('sessions');
|
||||
let isImported = false;
|
||||
let isEdited = false;
|
||||
if (options != undefined){
|
||||
if (options.indexOf('imported') > -1) isImported = true;
|
||||
if (options.indexOf('edited') > -1) isEdited = true;
|
||||
}
|
||||
// sessionName can be changed by the user in the manager window
|
||||
store.add({
|
||||
creationTime: date,
|
||||
sessionName: host,
|
||||
serverName: host,
|
||||
isImported: isImported,
|
||||
isEdited: isEdited,
|
||||
version: 6});
|
||||
tx.oncomplete = function() {
|
||||
resolve();
|
||||
};
|
||||
tx.onerror = function(event) {
|
||||
alert('error storing note ' + event.target.errorCode);
|
||||
reject();
|
||||
};
|
||||
});
|
||||
await new Promise(function(resolve, reject) {
|
||||
const tx2 = db_blobs.transaction(['sessions'], 'readwrite');
|
||||
const store2 = tx2.objectStore('sessions');
|
||||
store2.add({
|
||||
creationTime: date,
|
||||
serverName:host,
|
||||
request:request,
|
||||
response:response,
|
||||
pgsg:pgsg});
|
||||
tx2.oncomplete = function() {
|
||||
resolve();
|
||||
};
|
||||
tx2.onerror = function(event) {
|
||||
alert('error storing note ' + event.target.errorCode);
|
||||
reject();
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export async function getSession(idx){
|
||||
return await new Promise(function(resolve, reject) {
|
||||
|
||||
const tx = db.transaction(['sessions'], 'readonly');
|
||||
const store = tx.objectStore('sessions');
|
||||
const req = store.get(idx);
|
||||
req.onsuccess = function(event) {
|
||||
const entry = event.target.result;
|
||||
if (entry) {
|
||||
console.log(entry);
|
||||
resolve(entry);
|
||||
} else {
|
||||
console.log('entry 1 not found');
|
||||
resolve(null);
|
||||
}
|
||||
};
|
||||
req.onerror = function(event) {
|
||||
console.log('error getting entry 1 ' + event.target.errorCode);
|
||||
reject('error getting entry 1 ' + event.target.errorCode);
|
||||
};
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// get data from blob store
|
||||
export async function getSessionBlob(idx){
|
||||
|
||||
return await new Promise(function(resolve, reject) {
|
||||
|
||||
const tx = db_blobs.transaction(['sessions'], 'readonly');
|
||||
const store = tx.objectStore('sessions');
|
||||
const req = store.get(idx);
|
||||
req.onsuccess = function(event) {
|
||||
const entry = event.target.result;
|
||||
if (entry) {
|
||||
resolve(entry);
|
||||
} else {
|
||||
console.log('note 1 not found');
|
||||
resolve(null);
|
||||
}
|
||||
};
|
||||
req.onerror = function(event) {
|
||||
console.log('error getting entry 1 ' + event.target.errorCode);
|
||||
reject('error getting entry 1 ' + event.target.errorCode);
|
||||
};
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export async function getPref(pref){
|
||||
return await new Promise(function(resolve, reject) {
|
||||
|
||||
let tx = db.transaction(['preferences'], 'readonly');
|
||||
let store = tx.objectStore('preferences');
|
||||
let req = store.get(pref);
|
||||
req.onsuccess = function(event) {
|
||||
let entry = event.target.result;
|
||||
if (entry) {
|
||||
console.log(entry);
|
||||
resolve(entry.value);
|
||||
} else {
|
||||
resolve(null);
|
||||
}
|
||||
};
|
||||
req.onerror = function(event) {
|
||||
console.log('error getting entry 1 ' + event.target.errorCode);
|
||||
reject('error getting entry 1 ' + event.target.errorCode);
|
||||
};
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export async function setPref(pref, newvalue) {
|
||||
await new Promise(function(resolve, reject) {
|
||||
|
||||
const tx = db.transaction(['preferences'], 'readwrite');
|
||||
const store = tx.objectStore('preferences');
|
||||
const request = store.get(pref);
|
||||
|
||||
request.onsuccess = function(event) {
|
||||
// Get the old value that we want to update
|
||||
const data = event.target.result;
|
||||
|
||||
// update the value(s) in the object that you want to change
|
||||
data.value = newvalue;
|
||||
|
||||
// Put this updated object back into the database.
|
||||
const requestUpdate = store.put(data);
|
||||
requestUpdate.onerror = function(event) {
|
||||
// Do something with the error
|
||||
reject();
|
||||
};
|
||||
requestUpdate.onsuccess = function(event) {
|
||||
// Success - the data is updated!
|
||||
resolve();
|
||||
};
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
export async function renameSession(id, newname) {
|
||||
await new Promise(function(resolve, reject) {
|
||||
// Start a database transaction and get the notes object store
|
||||
const tx = db.transaction(['sessions'], 'readwrite');
|
||||
const sessions = tx.objectStore('sessions');
|
||||
const request = sessions.get(id);
|
||||
|
||||
request.onsuccess = function(event) {
|
||||
// Get the old value that we want to update
|
||||
const data = event.target.result;
|
||||
|
||||
// update the value(s) in the object that you want to change
|
||||
data.sessionName = newname;
|
||||
|
||||
// Put this updated object back into the database.
|
||||
const requestUpdate = sessions.put(data);
|
||||
requestUpdate.onerror = function(event) {
|
||||
// Do something with the error
|
||||
reject();
|
||||
};
|
||||
requestUpdate.onsuccess = function(event) {
|
||||
// Success - the data is updated!
|
||||
resolve();
|
||||
};
|
||||
};
|
||||
});
|
||||
}
|
||||
342
core/oracles.js
Normal file
342
core/oracles.js
Normal file
@@ -0,0 +1,342 @@
|
||||
import {global} from './globals.js';
|
||||
import {ba2str, b64decode, assert, ba2int, verifyAttestationDoc, ba2hex, eq,
|
||||
sha256} from './utils.js';
|
||||
|
||||
// rootOfTrust id the id of an EBS snapshot
|
||||
// essentially the whole oracle verification procedure boils down to proving that an EC2 instance was
|
||||
// launched from an AMI which was created from the "rootOfTrust" snapshot id.
|
||||
const rootOfTrust = 'snap-0ccb00d0e0fb4d4da';
|
||||
// URLFetcher trusted enclave measurements, see
|
||||
// https://github.com/tlsnotary/URLFetcher
|
||||
const URLFetcherPCR0 = 'f70217239e8a1cb0f3c010b842a279e2b8d30d3700d7e4722fef22291763479a13783dc76d5219fabbd7e5aa92a7b255';
|
||||
const URLFetcherPCR1 = 'c35e620586e91ed40ca5ce360eedf77ba673719135951e293121cb3931220b00f87b5a15e94e25c01fecd08fc9139342';
|
||||
const URLFetcherPCR2 = 'efba114128ccd6af1d1366a12c1ac89e4a4ca5ea1434d779efadfd3ec0d1da5b7c0d8525239fac29ffde2946e07d1c16';
|
||||
|
||||
|
||||
// assuming both events happened on the same day, get the time
|
||||
// difference between them in seconds
|
||||
// the time string looks like "2015-04-15T19:00:59.000Z"
|
||||
function getSecondsDelta(later, sooner) {
|
||||
assert(later.length == 24);
|
||||
if (later.slice(0, 11) !== sooner.slice(0, 11)) {
|
||||
return 999999; // not on the same day
|
||||
}
|
||||
const laterTime = later.slice(11, 19).split(':');
|
||||
const soonerTime = sooner.slice(11, 19).split(':');
|
||||
const laterSecs = parseInt(laterTime[0]) * 3600 + parseInt(laterTime[1]) * 60 + parseInt(laterTime[2]);
|
||||
const soonerSecs = parseInt(soonerTime[0]) * 3600 + parseInt(soonerTime[1]) * 60 + parseInt(soonerTime[2]);
|
||||
return laterSecs - soonerSecs;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function checkDescribeInstances(xmlDoc, instanceId, imageId, volumeId) {
|
||||
try {
|
||||
assert(xmlDoc.getElementsByTagName('DescribeInstancesResponse').length == 1);
|
||||
const rs = xmlDoc.getElementsByTagName('reservationSet');
|
||||
assert(rs.length === 1);
|
||||
const rs_items = rs[0].children;
|
||||
assert(rs_items.length === 1);
|
||||
var ownerId = rs_items[0].getElementsByTagName('ownerId')[0].textContent;
|
||||
const isets = rs_items[0].getElementsByTagName('instancesSet');
|
||||
assert(isets.length === 1);
|
||||
const instances = isets[0].children;
|
||||
assert(instances.length === 1);
|
||||
const parent = instances[0];
|
||||
assert(parent.getElementsByTagName('instanceId')[0].textContent === instanceId);
|
||||
assert(parent.getElementsByTagName('imageId')[0].textContent === imageId);
|
||||
assert(parent.getElementsByTagName('instanceState')[0].getElementsByTagName('name')[0].textContent === 'running');
|
||||
var launchTime = parent.getElementsByTagName('launchTime')[0].textContent;
|
||||
assert(parent.getElementsByTagName('rootDeviceType')[0].textContent === 'ebs');
|
||||
assert(parent.getElementsByTagName('rootDeviceName')[0].textContent === '/dev/sda1');
|
||||
const devices = parent.getElementsByTagName('blockDeviceMapping')[0].getElementsByTagName('item');
|
||||
assert(devices.length === 1);
|
||||
assert(devices[0].getElementsByTagName('deviceName')[0].textContent === '/dev/sda1');
|
||||
assert(devices[0].getElementsByTagName('ebs')[0].getElementsByTagName('status')[0].textContent === 'attached');
|
||||
var volAttachTime = devices[0].getElementsByTagName('ebs')[0].getElementsByTagName('attachTime')[0].textContent;
|
||||
assert(devices[0].getElementsByTagName('ebs')[0].getElementsByTagName('volumeId')[0].textContent === volumeId);
|
||||
// get seconds from "2015-04-15T19:00:59.000Z"
|
||||
assert(getSecondsDelta(volAttachTime, launchTime) <= 2);
|
||||
assert(parent.getElementsByTagName('virtualizationType')[0].textContent === 'hvm');
|
||||
} catch (e) {
|
||||
throw('checkDescribeInstances exception');
|
||||
}
|
||||
return {
|
||||
'ownerId': ownerId,
|
||||
'volAttachTime': volAttachTime,
|
||||
'launchTime': launchTime
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function checkDescribeVolumes(xmlDoc, instanceId, volumeId, volAttachTime, snapshotId) {
|
||||
try {
|
||||
assert(xmlDoc.getElementsByTagName('DescribeVolumesResponse').length == 1);
|
||||
const volumes = xmlDoc.getElementsByTagName('volumeSet')[0].children;
|
||||
assert(volumes.length === 1);
|
||||
const volume = volumes[0];
|
||||
assert(volume.getElementsByTagName('volumeId')[0].textContent === volumeId);
|
||||
assert(volume.getElementsByTagName('snapshotId')[0].textContent === snapshotId);
|
||||
assert(volume.getElementsByTagName('status')[0].textContent === 'in-use');
|
||||
const volCreateTime = volume.getElementsByTagName('createTime')[0].textContent;
|
||||
const attVolumes = volume.getElementsByTagName('attachmentSet')[0].getElementsByTagName('item');
|
||||
assert(attVolumes.length === 1);
|
||||
const attVolume = attVolumes[0];
|
||||
assert(attVolume.getElementsByTagName('volumeId')[0].textContent === volumeId);
|
||||
assert(attVolume.getElementsByTagName('instanceId')[0].textContent === instanceId);
|
||||
assert(attVolume.getElementsByTagName('device')[0].textContent === '/dev/sda1');
|
||||
assert(attVolume.getElementsByTagName('status')[0].textContent === 'attached');
|
||||
const attTime = attVolume.getElementsByTagName('attachTime')[0].textContent;
|
||||
assert(volAttachTime === attTime);
|
||||
// Crucial: volume was created from snapshot and attached at the same instant
|
||||
// this guarantees that there was no time window to modify it
|
||||
assert(getSecondsDelta(attTime, volCreateTime) === 0);
|
||||
} catch (e) {
|
||||
throw('checkDescribeVolumes exception');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function checkGetConsoleOutput(xmlDoc, instanceId) {
|
||||
try {
|
||||
assert(xmlDoc.getElementsByTagName('GetConsoleOutputResponse').length == 1);
|
||||
assert(xmlDoc.getElementsByTagName('instanceId')[0].textContent === instanceId);
|
||||
const b64data = xmlDoc.getElementsByTagName('output')[0].textContent;
|
||||
const logstr = ba2str(b64decode(b64data));
|
||||
// the only nvme* strings allowed are: nvme, nvme0, nvme0n1, nvme0n1p1
|
||||
// this ensures that instance has only one disk device. This is
|
||||
// a redundant check, because the patched ramdisk must halt the boot process if
|
||||
// it detects more than one disk device.
|
||||
const allowedSet = ['nvme', 'nvme0', 'nvme0n1', 'nvme0n1p1'];
|
||||
// match all substrings starting with nvme, folowed by a count of from 0 to 7 symbols from
|
||||
// the ranges 0-9 and a-z
|
||||
for (const match of [...logstr.matchAll(/nvme[0-9a-z]{0,7}/g)]){
|
||||
assert(match.length == 1);
|
||||
assert(allowedSet.includes(match[0]), 'disallowed nvme* string present in log');
|
||||
}
|
||||
|
||||
const sigmark = 'PageSigner public key for verification';
|
||||
const pkstartmark = '-----BEGIN PUBLIC KEY-----';
|
||||
const pkendmark = '-----END PUBLIC KEY-----';
|
||||
|
||||
const mark_start = logstr.search(sigmark);
|
||||
assert(mark_start !== -1);
|
||||
const pubkey_start = mark_start + logstr.slice(mark_start).search(pkstartmark);
|
||||
const pubkey_end = pubkey_start + logstr.slice(pubkey_start).search(pkendmark) + pkendmark.length;
|
||||
const chunk = logstr.slice(pubkey_start, pubkey_end);
|
||||
const lines = chunk.split('\n');
|
||||
let pk = pkstartmark + '\n';
|
||||
for (let i = 1; i < lines.length-1; i++) {
|
||||
const words = lines[i].split(' ');
|
||||
pk = pk + words[words.length-1] + '\n';
|
||||
}
|
||||
pk = pk + pkendmark;
|
||||
assert(pk.length > 0);
|
||||
const pubkeyPEM = pk.split('\r\n').join('\n');
|
||||
return pubkeyPEM;
|
||||
} catch (e) {
|
||||
throw('checkGetConsoleOutput exception');
|
||||
}
|
||||
}
|
||||
|
||||
// "userData" allows to pass an arbitrary script to the instance at launch. It MUST be empty.
|
||||
// This is a sanity check because the instance is stripped of the code which parses userData.
|
||||
function checkDescribeInstanceAttributeUserdata(xmlDoc, instanceId) {
|
||||
try {
|
||||
assert(xmlDoc.getElementsByTagName('DescribeInstanceAttributeResponse').length == 1);
|
||||
assert(xmlDoc.getElementsByTagName('instanceId')[0].textContent === instanceId);
|
||||
assert(xmlDoc.getElementsByTagName('userData')[0].textContent === '');
|
||||
} catch (e) {
|
||||
throw('checkDescribeInstanceAttributeUserdata exception');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function checkDescribeInstanceAttributeKernel(xmlDoc, instanceId) {
|
||||
try {
|
||||
assert(xmlDoc.getElementsByTagName('DescribeInstanceAttributeResponse').length == 1);
|
||||
assert(xmlDoc.getElementsByTagName('instanceId')[0].textContent === instanceId);
|
||||
assert(xmlDoc.getElementsByTagName('kernel')[0].textContent === '');
|
||||
} catch (e) {
|
||||
throw('checkDescribeInstanceAttributeKernel exception');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function checkDescribeInstanceAttributeRamdisk(xmlDoc, instanceId) {
|
||||
try {
|
||||
assert(xmlDoc.getElementsByTagName('DescribeInstanceAttributeResponse').length == 1);
|
||||
assert(xmlDoc.getElementsByTagName('instanceId')[0].textContent === instanceId);
|
||||
assert(xmlDoc.getElementsByTagName('ramdisk')[0].textContent === '');
|
||||
} catch (e) {
|
||||
throw('checkDescribeInstanceAttributeRamdisk exception');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function checkGetUser(xmlDoc, ownerId) {
|
||||
try {
|
||||
assert(xmlDoc.getElementsByTagName('GetUserResponse').length == 1);
|
||||
assert(xmlDoc.getElementsByTagName('UserId')[0].textContent === ownerId);
|
||||
assert(xmlDoc.getElementsByTagName('Arn')[0].textContent.slice(-(ownerId.length + ':root'.length)) === ownerId + ':root');
|
||||
} catch (e) {
|
||||
throw('checkGetUser exception');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function checkDescribeImages(xmlDoc, imageId, snapshotId){
|
||||
try {
|
||||
assert(xmlDoc.getElementsByTagName('DescribeImagesResponse').length == 1);
|
||||
const images = xmlDoc.getElementsByTagName('imagesSet')[0].children;
|
||||
assert(images.length == 1);
|
||||
const image = images[0];
|
||||
assert(image.getElementsByTagName('imageId')[0].textContent == imageId);
|
||||
assert(image.getElementsByTagName('rootDeviceName')[0].textContent == '/dev/sda1');
|
||||
const devices = image.getElementsByTagName('blockDeviceMapping')[0].children;
|
||||
assert(devices.length == 1);
|
||||
const device = devices[0];
|
||||
const ebs = device.getElementsByTagName('ebs')[0];
|
||||
assert(ebs.getElementsByTagName('snapshotId')[0].textContent == snapshotId);
|
||||
} catch (e) {
|
||||
throw('checkDescribeImages exception');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
async function fetch_and_parse(obj){
|
||||
// we don't fetch it ourselves anymore. URLFetcher already did that for us.
|
||||
// const req = await fetch(obj.request);
|
||||
// const text = await req.text();
|
||||
const xmlDoc = new DOMParser().parseFromString(obj.response, 'text/xml');
|
||||
return xmlDoc;
|
||||
}
|
||||
|
||||
export async function getURLFetcherDoc(IP){
|
||||
// get URLFetcher document containing attestation for AWS HTTP API URLs needed to
|
||||
// verify that the oracle was correctly set up.
|
||||
// https://github.com/tlsnotary/URLFetcher
|
||||
const resp = await fetch('http://' + IP + ':' + global.defaultNotaryPort + '/getURLFetcherDoc', {
|
||||
method: 'POST',
|
||||
mode: 'cors',
|
||||
cache: 'no-store',
|
||||
});
|
||||
return new Uint8Array(await resp.arrayBuffer());
|
||||
}
|
||||
|
||||
export async function verify_oracle(URLFetcherDoc) {
|
||||
// URLFetcherDoc is a concatenation of 4-byte transcript length | transcript | attestation doc
|
||||
const transcriptLen = ba2int(URLFetcherDoc.slice(0,4));
|
||||
const transcript = URLFetcherDoc.slice(4,4+transcriptLen);
|
||||
const attestation = URLFetcherDoc.slice(4+transcriptLen);
|
||||
|
||||
// transcript is a JSON array for each request[ {"request":<URL>, "response":<text>} , {...}]
|
||||
const transJSON = JSON.parse(ba2str(transcript));
|
||||
// find which URL corresponds to which API call
|
||||
const markers = [
|
||||
{'DescribeInstances': 'DI'},
|
||||
{'DescribeVolumes': 'DV'},
|
||||
{'GetConsoleOutput': 'GCO'},
|
||||
{'GetUser': 'GU'},
|
||||
{'userData': 'DIAud'},
|
||||
{'kernel': 'DIAk'},
|
||||
{'ramdisk': 'DIAr'},
|
||||
{'DescribeImages': 'DImg'}];
|
||||
const o = {};
|
||||
for (let i=0; i < markers.length; i++){
|
||||
const key = Object.keys(markers[i]);
|
||||
for (let j=0; j < transJSON.length; j++){
|
||||
if (transJSON[j].request.indexOf(key) > -1){
|
||||
o[markers[i][key]] = transJSON[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(Object.keys(o).length === markers.length);
|
||||
|
||||
|
||||
// check that the URLs are formatted in a canonical way
|
||||
// Note that AWS expects URL params to be sorted alphabetically. If we put them in
|
||||
// arbitrary order, the query will be rejected
|
||||
|
||||
// "AWSAccessKeyId" should be the same in all URLs to prove that the queries are made
|
||||
// on behalf of AWS user "root". Otherwise, a potential attack opens up when AWS APi calls
|
||||
// are made on behalf of a user with limited privileges for whom the API report only
|
||||
// partial information.
|
||||
const AWSAccessKeyId = o.DI.request.match(new RegExp('^https://ec2.us-east-1.amazonaws.com/\\?AWSAccessKeyId=[A-Z0-9]{20}'))[0].split('=')[1];
|
||||
// We only allow oracles instantiated from TLSNotary's AWS account.
|
||||
assert(AWSAccessKeyId === 'AKIAI2NJVYXCCAQDCC5Q');
|
||||
assert(AWSAccessKeyId.length === 20);
|
||||
|
||||
const instanceId = o.DI.request.match(new RegExp('^https://ec2.us-east-1.amazonaws.com/\\?AWSAccessKeyId='+AWSAccessKeyId+'&Action=DescribeInstances&Expires=2030-01-01&InstanceId=i-[a-f0-9]{17}'))[0].split('=')[4];
|
||||
assert(instanceId.length === 19);
|
||||
|
||||
const volumeId = o.DV.request.match(new RegExp('^https://ec2.us-east-1.amazonaws.com/\\?AWSAccessKeyId='+AWSAccessKeyId+'&Action=DescribeVolumes&Expires=2030-01-01&SignatureMethod=HmacSHA256&SignatureVersion=2&Version=2014-10-01&VolumeId=vol-[a-f0-9]{17}'))[0].split('=')[7];
|
||||
assert(volumeId.length === 21);
|
||||
|
||||
const amiId = o.DImg.request.match(new RegExp('^https://ec2.us-east-1.amazonaws.com/\\?AWSAccessKeyId='+AWSAccessKeyId+'&Action=DescribeImages&Expires=2030-01-01&ImageId.1=ami-[a-f0-9]{17}'))[0].split('=')[4];
|
||||
assert(amiId.length === 21);
|
||||
|
||||
assert(new RegExp('^https://ec2.us-east-1.amazonaws.com/\\?AWSAccessKeyId='+AWSAccessKeyId+'&Action=DescribeInstances&Expires=2030-01-01&InstanceId='+instanceId+'&SignatureMethod=HmacSHA256&SignatureVersion=2&Version=2014-10-01&Signature=[a-zA-Z0-9%]{46,56}$').test(o.DI.request));
|
||||
|
||||
assert(new RegExp('^https://ec2.us-east-1.amazonaws.com/\\?AWSAccessKeyId='+AWSAccessKeyId+'&Action=DescribeVolumes&Expires=2030-01-01&SignatureMethod=HmacSHA256&SignatureVersion=2&Version=2014-10-01&VolumeId='+volumeId+'&Signature=[a-zA-Z0-9%]{46,56}$').test(o.DV.request));
|
||||
|
||||
assert(new RegExp('^https://ec2.us-east-1.amazonaws.com/\\?AWSAccessKeyId='+AWSAccessKeyId+'&Action=GetConsoleOutput&Expires=2030-01-01&InstanceId='+instanceId+'&SignatureMethod=HmacSHA256&SignatureVersion=2&Version=2014-10-01&Signature=[a-zA-Z0-9%]{46,56}$').test(o.GCO.request));
|
||||
|
||||
assert(new RegExp('^https://iam.amazonaws.com/\\?AWSAccessKeyId='+AWSAccessKeyId+'&Action=GetUser&Expires=2030-01-01&SignatureMethod=HmacSHA256&SignatureVersion=2&Version=2010-05-08&Signature=[a-zA-Z0-9%]{46,56}$').test(o.GU.request));
|
||||
|
||||
assert(new RegExp('^https://ec2.us-east-1.amazonaws.com/\\?AWSAccessKeyId='+AWSAccessKeyId+'&Action=DescribeInstanceAttribute&Attribute=userData&Expires=2030-01-01&InstanceId='+instanceId+'&SignatureMethod=HmacSHA256&SignatureVersion=2&Version=2014-10-01&Signature=[a-zA-Z0-9%]{46,56}$').test(o.DIAud.request));
|
||||
|
||||
assert(new RegExp('^https://ec2.us-east-1.amazonaws.com/\\?AWSAccessKeyId='+AWSAccessKeyId+'&Action=DescribeInstanceAttribute&Attribute=kernel&Expires=2030-01-01&InstanceId='+instanceId+'&SignatureMethod=HmacSHA256&SignatureVersion=2&Version=2014-10-01&Signature=[a-zA-Z0-9%]{46,56}$').test(o.DIAk.request));
|
||||
|
||||
assert(new RegExp('^https://ec2.us-east-1.amazonaws.com/\\?AWSAccessKeyId='+AWSAccessKeyId+'&Action=DescribeInstanceAttribute&Attribute=ramdisk&Expires=2030-01-01&InstanceId='+instanceId+'&SignatureMethod=HmacSHA256&SignatureVersion=2&Version=2014-10-01&Signature=[a-zA-Z0-9%]{46,56}$').test(o.DIAr.request));
|
||||
|
||||
assert(new RegExp('^https://ec2.us-east-1.amazonaws.com/\\?AWSAccessKeyId='+AWSAccessKeyId+'&Action=DescribeImages&Expires=2030-01-01&ImageId.1='+amiId+'&SignatureMethod=HmacSHA256&SignatureVersion=2&Version=2014-10-01&Signature=[a-zA-Z0-9%]{46,56}$').test(o.DImg.request));
|
||||
|
||||
const xmlDocDI = await fetch_and_parse(o.DI);
|
||||
const rv = checkDescribeInstances(xmlDocDI, instanceId, amiId, volumeId);
|
||||
const volAttachTime = rv.volAttachTime;
|
||||
const ownerId = rv.ownerId;
|
||||
|
||||
const xmlDocDV = await fetch_and_parse(o.DV);
|
||||
checkDescribeVolumes(xmlDocDV, instanceId, volumeId, volAttachTime, rootOfTrust);
|
||||
|
||||
const xmlDocGU = await fetch_and_parse(o.GU);
|
||||
checkGetUser(xmlDocGU, ownerId);
|
||||
|
||||
const xmlDocGCO = await fetch_and_parse(o.GCO);
|
||||
const pubkeyPEM = checkGetConsoleOutput(xmlDocGCO, instanceId);
|
||||
|
||||
const xmlDocDIAud = await fetch_and_parse(o.DIAud);
|
||||
checkDescribeInstanceAttributeUserdata(xmlDocDIAud, instanceId);
|
||||
|
||||
const xmlDocDIAk = await fetch_and_parse(o.DIAk);
|
||||
checkDescribeInstanceAttributeKernel(xmlDocDIAk, instanceId);
|
||||
|
||||
const xmlDocDIAr = await fetch_and_parse(o.DIAr);
|
||||
checkDescribeInstanceAttributeRamdisk(xmlDocDIAr, instanceId);
|
||||
|
||||
const xmlDocDImg = await fetch_and_parse(o.DImg);
|
||||
checkDescribeImages(xmlDocDImg, amiId, rootOfTrust);
|
||||
|
||||
// verify the attestation document
|
||||
const attestRV = await verifyAttestationDoc(attestation);
|
||||
assert(eq(attestRV[0], await sha256(transcript)));
|
||||
assert(URLFetcherPCR0 === ba2hex(attestRV[1]));
|
||||
assert(URLFetcherPCR1 === ba2hex(attestRV[2]));
|
||||
assert(URLFetcherPCR2 === ba2hex(attestRV[3]));
|
||||
|
||||
console.log('oracle verification successfully finished');
|
||||
return pubkeyPEM;
|
||||
}
|
||||
|
||||
|
||||
if (typeof module !== 'undefined'){ // we are in node.js environment
|
||||
module.exports={
|
||||
check_oracle: verify_oracle,
|
||||
oracle,
|
||||
};
|
||||
}
|
||||
32
core/third-party/SOURCES.third-party
vendored
Normal file
32
core/third-party/SOURCES.third-party
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
pkijs folder contains files from the following sources:
|
||||
|
||||
bytestream.js from https://github.com/PeculiarVentures/ByteStream.js/blob/681f2d08b1102dcd39b8a57e989dcdeadf34623d/src/bytestream.js
|
||||
asn1.js from https://github.com/PeculiarVentures/ASN1.js/blob/5c64632d8d08955f07a9f80b9518a84d76f605cd/src/asn1.js
|
||||
pvutils.js from https://github.com/PeculiarVentures/pvutils/blob/2d15272c34f05581eb268802c5bcfab7c4c04e03/src/utils.js
|
||||
the rest of the *.js files are from
|
||||
https://github.com/PeculiarVentures/PKI.js/tree/fa83e1ef003c8b450832b8c878cd36b73aaa0dee/src
|
||||
|
||||
After putting all the files into the same folder, we changed the paths with
|
||||
sed -i 's#from "asn1js"#from "./asn1.js"#g' *
|
||||
sed -i 's#from "pvutils"#from "./pvutils.js"#g' *
|
||||
sed -i 's#from "bytestreamjs"#from "./bytestream.js"#g' *
|
||||
|
||||
|
||||
bigint-crypto-utils.esm.js from
|
||||
https://github.com/juanelas/bigint-crypto-utils/tree/954321199d4a8038c3d27113aec825ff2e5bf544/dist/bundles
|
||||
|
||||
https://github.com/Azero123/simple-js-ec-math
|
||||
browserify simple-js-ec-math/src/index.js --standalone ECSimple > simple-js-ec-math.js
|
||||
|
||||
https://raw.githubusercontent.com/dchest/fast-sha256-js/master/sha256.js > fastsha256.js
|
||||
|
||||
cbor.js and cose.js are used to verify the enclave attestation document
|
||||
cbor.js is from https://github.com/paroga/cbor-js/blob/master/cbor.js
|
||||
cose.js was built with browserify coseverify.js --standalone COSE > cose.js
|
||||
|
||||
pako.js ---> SOURCE???
|
||||
|
||||
certs.txt is Mozilla'a root store taken from
|
||||
https://ccadb-public.secure.force.com/mozilla/IncludedCACertificateReportPEMCSV
|
||||
|
||||
|
||||
406
core/third-party/cbor.js
vendored
Normal file
406
core/third-party/cbor.js
vendored
Normal file
@@ -0,0 +1,406 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014-2016 Patrick Gansterer <paroga@paroga.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
(function(global, undefined) { "use strict";
|
||||
var POW_2_24 = 5.960464477539063e-8,
|
||||
POW_2_32 = 4294967296,
|
||||
POW_2_53 = 9007199254740992;
|
||||
|
||||
function encode(value) {
|
||||
var data = new ArrayBuffer(256);
|
||||
var dataView = new DataView(data);
|
||||
var lastLength;
|
||||
var offset = 0;
|
||||
|
||||
function prepareWrite(length) {
|
||||
var newByteLength = data.byteLength;
|
||||
var requiredLength = offset + length;
|
||||
while (newByteLength < requiredLength)
|
||||
newByteLength <<= 1;
|
||||
if (newByteLength !== data.byteLength) {
|
||||
var oldDataView = dataView;
|
||||
data = new ArrayBuffer(newByteLength);
|
||||
dataView = new DataView(data);
|
||||
var uint32count = (offset + 3) >> 2;
|
||||
for (var i = 0; i < uint32count; ++i)
|
||||
dataView.setUint32(i << 2, oldDataView.getUint32(i << 2));
|
||||
}
|
||||
|
||||
lastLength = length;
|
||||
return dataView;
|
||||
}
|
||||
function commitWrite() {
|
||||
offset += lastLength;
|
||||
}
|
||||
function writeFloat64(value) {
|
||||
commitWrite(prepareWrite(8).setFloat64(offset, value));
|
||||
}
|
||||
function writeUint8(value) {
|
||||
commitWrite(prepareWrite(1).setUint8(offset, value));
|
||||
}
|
||||
function writeUint8Array(value) {
|
||||
var dataView = prepareWrite(value.length);
|
||||
for (var i = 0; i < value.length; ++i)
|
||||
dataView.setUint8(offset + i, value[i]);
|
||||
commitWrite();
|
||||
}
|
||||
function writeUint16(value) {
|
||||
commitWrite(prepareWrite(2).setUint16(offset, value));
|
||||
}
|
||||
function writeUint32(value) {
|
||||
commitWrite(prepareWrite(4).setUint32(offset, value));
|
||||
}
|
||||
function writeUint64(value) {
|
||||
var low = value % POW_2_32;
|
||||
var high = (value - low) / POW_2_32;
|
||||
var dataView = prepareWrite(8);
|
||||
dataView.setUint32(offset, high);
|
||||
dataView.setUint32(offset + 4, low);
|
||||
commitWrite();
|
||||
}
|
||||
function writeTypeAndLength(type, length) {
|
||||
if (length < 24) {
|
||||
writeUint8(type << 5 | length);
|
||||
} else if (length < 0x100) {
|
||||
writeUint8(type << 5 | 24);
|
||||
writeUint8(length);
|
||||
} else if (length < 0x10000) {
|
||||
writeUint8(type << 5 | 25);
|
||||
writeUint16(length);
|
||||
} else if (length < 0x100000000) {
|
||||
writeUint8(type << 5 | 26);
|
||||
writeUint32(length);
|
||||
} else {
|
||||
writeUint8(type << 5 | 27);
|
||||
writeUint64(length);
|
||||
}
|
||||
}
|
||||
|
||||
function encodeItem(value) {
|
||||
var i;
|
||||
|
||||
if (value === false)
|
||||
return writeUint8(0xf4);
|
||||
if (value === true)
|
||||
return writeUint8(0xf5);
|
||||
if (value === null)
|
||||
return writeUint8(0xf6);
|
||||
if (value === undefined)
|
||||
return writeUint8(0xf7);
|
||||
|
||||
switch (typeof value) {
|
||||
case "number":
|
||||
if (Math.floor(value) === value) {
|
||||
if (0 <= value && value <= POW_2_53)
|
||||
return writeTypeAndLength(0, value);
|
||||
if (-POW_2_53 <= value && value < 0)
|
||||
return writeTypeAndLength(1, -(value + 1));
|
||||
}
|
||||
writeUint8(0xfb);
|
||||
return writeFloat64(value);
|
||||
|
||||
case "string":
|
||||
var utf8data = [];
|
||||
for (i = 0; i < value.length; ++i) {
|
||||
var charCode = value.charCodeAt(i);
|
||||
if (charCode < 0x80) {
|
||||
utf8data.push(charCode);
|
||||
} else if (charCode < 0x800) {
|
||||
utf8data.push(0xc0 | charCode >> 6);
|
||||
utf8data.push(0x80 | charCode & 0x3f);
|
||||
} else if (charCode < 0xd800) {
|
||||
utf8data.push(0xe0 | charCode >> 12);
|
||||
utf8data.push(0x80 | (charCode >> 6) & 0x3f);
|
||||
utf8data.push(0x80 | charCode & 0x3f);
|
||||
} else {
|
||||
charCode = (charCode & 0x3ff) << 10;
|
||||
charCode |= value.charCodeAt(++i) & 0x3ff;
|
||||
charCode += 0x10000;
|
||||
|
||||
utf8data.push(0xf0 | charCode >> 18);
|
||||
utf8data.push(0x80 | (charCode >> 12) & 0x3f);
|
||||
utf8data.push(0x80 | (charCode >> 6) & 0x3f);
|
||||
utf8data.push(0x80 | charCode & 0x3f);
|
||||
}
|
||||
}
|
||||
|
||||
writeTypeAndLength(3, utf8data.length);
|
||||
return writeUint8Array(utf8data);
|
||||
|
||||
default:
|
||||
var length;
|
||||
if (Array.isArray(value)) {
|
||||
length = value.length;
|
||||
writeTypeAndLength(4, length);
|
||||
for (i = 0; i < length; ++i)
|
||||
encodeItem(value[i]);
|
||||
} else if (value instanceof Uint8Array) {
|
||||
writeTypeAndLength(2, value.length);
|
||||
writeUint8Array(value);
|
||||
} else {
|
||||
var keys = Object.keys(value);
|
||||
length = keys.length;
|
||||
writeTypeAndLength(5, length);
|
||||
for (i = 0; i < length; ++i) {
|
||||
var key = keys[i];
|
||||
encodeItem(key);
|
||||
encodeItem(value[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
encodeItem(value);
|
||||
|
||||
if ("slice" in data)
|
||||
return data.slice(0, offset);
|
||||
|
||||
var ret = new ArrayBuffer(offset);
|
||||
var retView = new DataView(ret);
|
||||
for (var i = 0; i < offset; ++i)
|
||||
retView.setUint8(i, dataView.getUint8(i));
|
||||
return ret;
|
||||
}
|
||||
|
||||
function decode(data, tagger, simpleValue) {
|
||||
var dataView = new DataView(data);
|
||||
var offset = 0;
|
||||
|
||||
if (typeof tagger !== "function")
|
||||
tagger = function(value) { return value; };
|
||||
if (typeof simpleValue !== "function")
|
||||
simpleValue = function() { return undefined; };
|
||||
|
||||
function commitRead(length, value) {
|
||||
offset += length;
|
||||
return value;
|
||||
}
|
||||
function readArrayBuffer(length) {
|
||||
return commitRead(length, new Uint8Array(data, offset, length));
|
||||
}
|
||||
function readFloat16() {
|
||||
var tempArrayBuffer = new ArrayBuffer(4);
|
||||
var tempDataView = new DataView(tempArrayBuffer);
|
||||
var value = readUint16();
|
||||
|
||||
var sign = value & 0x8000;
|
||||
var exponent = value & 0x7c00;
|
||||
var fraction = value & 0x03ff;
|
||||
|
||||
if (exponent === 0x7c00)
|
||||
exponent = 0xff << 10;
|
||||
else if (exponent !== 0)
|
||||
exponent += (127 - 15) << 10;
|
||||
else if (fraction !== 0)
|
||||
return (sign ? -1 : 1) * fraction * POW_2_24;
|
||||
|
||||
tempDataView.setUint32(0, sign << 16 | exponent << 13 | fraction << 13);
|
||||
return tempDataView.getFloat32(0);
|
||||
}
|
||||
function readFloat32() {
|
||||
return commitRead(4, dataView.getFloat32(offset));
|
||||
}
|
||||
function readFloat64() {
|
||||
return commitRead(8, dataView.getFloat64(offset));
|
||||
}
|
||||
function readUint8() {
|
||||
return commitRead(1, dataView.getUint8(offset));
|
||||
}
|
||||
function readUint16() {
|
||||
return commitRead(2, dataView.getUint16(offset));
|
||||
}
|
||||
function readUint32() {
|
||||
return commitRead(4, dataView.getUint32(offset));
|
||||
}
|
||||
function readUint64() {
|
||||
return readUint32() * POW_2_32 + readUint32();
|
||||
}
|
||||
function readBreak() {
|
||||
if (dataView.getUint8(offset) !== 0xff)
|
||||
return false;
|
||||
offset += 1;
|
||||
return true;
|
||||
}
|
||||
function readLength(additionalInformation) {
|
||||
if (additionalInformation < 24)
|
||||
return additionalInformation;
|
||||
if (additionalInformation === 24)
|
||||
return readUint8();
|
||||
if (additionalInformation === 25)
|
||||
return readUint16();
|
||||
if (additionalInformation === 26)
|
||||
return readUint32();
|
||||
if (additionalInformation === 27)
|
||||
return readUint64();
|
||||
if (additionalInformation === 31)
|
||||
return -1;
|
||||
throw "Invalid length encoding";
|
||||
}
|
||||
function readIndefiniteStringLength(majorType) {
|
||||
var initialByte = readUint8();
|
||||
if (initialByte === 0xff)
|
||||
return -1;
|
||||
var length = readLength(initialByte & 0x1f);
|
||||
if (length < 0 || (initialByte >> 5) !== majorType)
|
||||
throw "Invalid indefinite length element";
|
||||
return length;
|
||||
}
|
||||
|
||||
function appendUtf16Data(utf16data, length) {
|
||||
for (var i = 0; i < length; ++i) {
|
||||
var value = readUint8();
|
||||
if (value & 0x80) {
|
||||
if (value < 0xe0) {
|
||||
value = (value & 0x1f) << 6
|
||||
| (readUint8() & 0x3f);
|
||||
length -= 1;
|
||||
} else if (value < 0xf0) {
|
||||
value = (value & 0x0f) << 12
|
||||
| (readUint8() & 0x3f) << 6
|
||||
| (readUint8() & 0x3f);
|
||||
length -= 2;
|
||||
} else {
|
||||
value = (value & 0x0f) << 18
|
||||
| (readUint8() & 0x3f) << 12
|
||||
| (readUint8() & 0x3f) << 6
|
||||
| (readUint8() & 0x3f);
|
||||
length -= 3;
|
||||
}
|
||||
}
|
||||
|
||||
if (value < 0x10000) {
|
||||
utf16data.push(value);
|
||||
} else {
|
||||
value -= 0x10000;
|
||||
utf16data.push(0xd800 | (value >> 10));
|
||||
utf16data.push(0xdc00 | (value & 0x3ff));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function decodeItem() {
|
||||
var initialByte = readUint8();
|
||||
var majorType = initialByte >> 5;
|
||||
var additionalInformation = initialByte & 0x1f;
|
||||
var i;
|
||||
var length;
|
||||
|
||||
if (majorType === 7) {
|
||||
switch (additionalInformation) {
|
||||
case 25:
|
||||
return readFloat16();
|
||||
case 26:
|
||||
return readFloat32();
|
||||
case 27:
|
||||
return readFloat64();
|
||||
}
|
||||
}
|
||||
|
||||
length = readLength(additionalInformation);
|
||||
if (length < 0 && (majorType < 2 || 6 < majorType))
|
||||
throw "Invalid length";
|
||||
|
||||
switch (majorType) {
|
||||
case 0:
|
||||
return length;
|
||||
case 1:
|
||||
return -1 - length;
|
||||
case 2:
|
||||
if (length < 0) {
|
||||
var elements = [];
|
||||
var fullArrayLength = 0;
|
||||
while ((length = readIndefiniteStringLength(majorType)) >= 0) {
|
||||
fullArrayLength += length;
|
||||
elements.push(readArrayBuffer(length));
|
||||
}
|
||||
var fullArray = new Uint8Array(fullArrayLength);
|
||||
var fullArrayOffset = 0;
|
||||
for (i = 0; i < elements.length; ++i) {
|
||||
fullArray.set(elements[i], fullArrayOffset);
|
||||
fullArrayOffset += elements[i].length;
|
||||
}
|
||||
return fullArray;
|
||||
}
|
||||
return readArrayBuffer(length);
|
||||
case 3:
|
||||
var utf16data = [];
|
||||
if (length < 0) {
|
||||
while ((length = readIndefiniteStringLength(majorType)) >= 0)
|
||||
appendUtf16Data(utf16data, length);
|
||||
} else
|
||||
appendUtf16Data(utf16data, length);
|
||||
return String.fromCharCode.apply(null, utf16data);
|
||||
case 4:
|
||||
var retArray;
|
||||
if (length < 0) {
|
||||
retArray = [];
|
||||
while (!readBreak())
|
||||
retArray.push(decodeItem());
|
||||
} else {
|
||||
retArray = new Array(length);
|
||||
for (i = 0; i < length; ++i)
|
||||
retArray[i] = decodeItem();
|
||||
}
|
||||
return retArray;
|
||||
case 5:
|
||||
var retObject = {};
|
||||
for (i = 0; i < length || length < 0 && !readBreak(); ++i) {
|
||||
var key = decodeItem();
|
||||
retObject[key] = decodeItem();
|
||||
}
|
||||
return retObject;
|
||||
case 6:
|
||||
return tagger(decodeItem(), length);
|
||||
case 7:
|
||||
switch (length) {
|
||||
case 20:
|
||||
return false;
|
||||
case 21:
|
||||
return true;
|
||||
case 22:
|
||||
return null;
|
||||
case 23:
|
||||
return undefined;
|
||||
default:
|
||||
return simpleValue(length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var ret = decodeItem();
|
||||
if (offset !== data.byteLength)
|
||||
throw "Remaining bytes";
|
||||
return ret;
|
||||
}
|
||||
|
||||
var obj = { encode: encode, decode: decode };
|
||||
|
||||
if (typeof define === "function" && define.amd)
|
||||
define("cbor/cbor", obj);
|
||||
else if (typeof module !== "undefined" && module.exports)
|
||||
module.exports = obj;
|
||||
else if (!global.CBOR)
|
||||
global.CBOR = obj;
|
||||
|
||||
})(this);
|
||||
3803
core/third-party/certs.txt
vendored
Normal file
3803
core/third-party/certs.txt
vendored
Normal file
File diff suppressed because it is too large
Load Diff
76
core/third-party/chacha.js
vendored
Normal file
76
core/third-party/chacha.js
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
/* This is free and unencumbered software released into the public domain. */
|
||||
"use strict";
|
||||
const CHACHA_ROUNDS = 20;
|
||||
const CHACHA_KEYSIZE = 32;
|
||||
const CHACHA_IVSIZE = 8;
|
||||
|
||||
/**
|
||||
* Create a new ChaCha generator seeded from the given KEY and IV.
|
||||
* Both KEY and IV must be ArrayBuffer objects of at least the
|
||||
* appropriate byte lengths (CHACHA_KEYSIZE, CHACHA_IVSIZE). Bytes
|
||||
* beyond the specified length are ignored.
|
||||
*
|
||||
* Returns a closure that takes no arguments. This closure, when
|
||||
* invoked, returns a 64-byte ArrayBuffer of the next 64 bytes of
|
||||
* output. Note: This buffer object is "owned" by the closure, and
|
||||
* the same buffer object is always returned, each time filled with
|
||||
* fresh output.
|
||||
*/
|
||||
function ChaCha(key, iv) {
|
||||
if (key.byteLength < CHACHA_KEYSIZE)
|
||||
throw new Error('key too short');
|
||||
if (iv.byteLength < CHACHA_IVSIZE)
|
||||
throw new Error('IV too short');
|
||||
const state = new Uint32Array(16);
|
||||
let view = new DataView(key);
|
||||
state[ 0] = 0x61707865; // "expand 32-byte k"
|
||||
state[ 1] = 0x3320646e; //
|
||||
state[ 2] = 0x79622d32; //
|
||||
state[ 3] = 0x6b206574; //
|
||||
state[ 4] = view.getUint32( 0, true);
|
||||
state[ 5] = view.getUint32( 4, true);
|
||||
state[ 6] = view.getUint32( 8, true);
|
||||
state[ 7] = view.getUint32(12, true);
|
||||
state[ 8] = view.getUint32(16, true);
|
||||
state[ 9] = view.getUint32(20, true);
|
||||
state[10] = view.getUint32(24, true);
|
||||
state[11] = view.getUint32(28, true);
|
||||
view = new DataView(iv);
|
||||
state[14] = view.getUint32( 0, true);
|
||||
state[15] = view.getUint32( 4, true);
|
||||
|
||||
/* Generator */
|
||||
const output = new Uint32Array(16);
|
||||
const outview = new DataView(output.buffer);
|
||||
return function() {
|
||||
function quarterround(x, a, b, c, d) {
|
||||
function rotate(v, n) { return (v << n) | (v >>> (32 - n)); }
|
||||
x[a] += x[b]; x[d] = rotate(x[d] ^ x[a], 16);
|
||||
x[c] += x[d]; x[b] = rotate(x[b] ^ x[c], 12);
|
||||
x[a] += x[b]; x[d] = rotate(x[d] ^ x[a], 8);
|
||||
x[c] += x[d]; x[b] = rotate(x[b] ^ x[c], 7);
|
||||
}
|
||||
output.set(state);
|
||||
for (let i = 0; i < CHACHA_ROUNDS; i += 2) {
|
||||
quarterround(output, 0, 4, 8, 12);
|
||||
quarterround(output, 1, 5, 9, 13);
|
||||
quarterround(output, 2, 6, 10, 14);
|
||||
quarterround(output, 3, 7, 11, 15);
|
||||
quarterround(output, 0, 5, 10, 15);
|
||||
quarterround(output, 1, 6, 11, 12);
|
||||
quarterround(output, 2, 7, 8, 13);
|
||||
quarterround(output, 3, 4, 9, 14);
|
||||
}
|
||||
for (let i = 0; i < 16; i++)
|
||||
outview.setUint32(i * 4, output[i] + state[i], true);
|
||||
state[12]++;
|
||||
if (state[12] == 0) {
|
||||
state[13]++;
|
||||
if (state[13] == 0) {
|
||||
/* One zebibyte of output reached! */
|
||||
throw new Error('output exhausted');
|
||||
}
|
||||
}
|
||||
return output.buffer;
|
||||
}
|
||||
}
|
||||
36781
core/third-party/cose.js
vendored
Normal file
36781
core/third-party/cose.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
31
core/third-party/coseverify.js
vendored
Normal file
31
core/third-party/coseverify.js
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
// this file is not used by the extension, it serves as an input to to create cose.js with:
|
||||
// browserify coseverify.js --standalone COSE > cose.js
|
||||
|
||||
const cose = require('cose-js');
|
||||
|
||||
// x,y,doc is an ArrayBuffer
|
||||
const verify = function (x, y, doc){
|
||||
const verifier = {
|
||||
'key': {
|
||||
'x': Buffer.from(x),
|
||||
'y': Buffer.from(y)
|
||||
}
|
||||
};
|
||||
|
||||
cose.sign.verify(
|
||||
Buffer.from(doc),
|
||||
verifier,
|
||||
{defaultType: 18})
|
||||
.then((buf) => {
|
||||
console.log("Verification successful")
|
||||
//console.log('Verified message: ' + buf.toString('utf8'));
|
||||
}).catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
if (typeof module !== 'undefined'){ //we are in node.js environment
|
||||
module.exports={
|
||||
verify
|
||||
}
|
||||
}
|
||||
427
core/third-party/fastsha256.js
vendored
Normal file
427
core/third-party/fastsha256.js
vendored
Normal file
@@ -0,0 +1,427 @@
|
||||
(function (root, factory) {
|
||||
// Hack to make all exports of this module sha256 function object properties.
|
||||
var exports = {};
|
||||
factory(exports);
|
||||
var fastsha256 = exports["default"];
|
||||
for (var k in exports) {
|
||||
fastsha256[k] = exports[k];
|
||||
}
|
||||
|
||||
if (typeof module === 'object' && typeof module.exports === 'object') {
|
||||
module.exports = fastsha256;
|
||||
} else if (typeof define === 'function' && define.amd) {
|
||||
define(function() { return fastsha256; });
|
||||
} else {
|
||||
root.fastsha256 = fastsha256;
|
||||
}
|
||||
})(this, function(exports) {
|
||||
"use strict";
|
||||
exports.__esModule = true;
|
||||
// SHA-256 (+ HMAC and PBKDF2) for JavaScript.
|
||||
//
|
||||
// Written in 2014-2016 by Dmitry Chestnykh.
|
||||
// Public domain, no warranty.
|
||||
//
|
||||
// Functions (accept and return Uint8Arrays):
|
||||
//
|
||||
// sha256(message) -> hash
|
||||
// sha256.hmac(key, message) -> mac
|
||||
// sha256.pbkdf2(password, salt, rounds, dkLen) -> dk
|
||||
//
|
||||
// Classes:
|
||||
//
|
||||
// new sha256.Hash()
|
||||
// new sha256.HMAC(key)
|
||||
//
|
||||
exports.digestLength = 32;
|
||||
exports.blockSize = 64;
|
||||
// SHA-256 constants
|
||||
var K = new Uint32Array([
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b,
|
||||
0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01,
|
||||
0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7,
|
||||
0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
|
||||
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152,
|
||||
0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
|
||||
0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc,
|
||||
0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819,
|
||||
0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08,
|
||||
0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f,
|
||||
0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
||||
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||
]);
|
||||
function hashBlocks(w, v, p, pos, len) {
|
||||
var a, b, c, d, e, f, g, h, u, i, j, t1, t2;
|
||||
while (len >= 64) {
|
||||
a = v[0];
|
||||
b = v[1];
|
||||
c = v[2];
|
||||
d = v[3];
|
||||
e = v[4];
|
||||
f = v[5];
|
||||
g = v[6];
|
||||
h = v[7];
|
||||
for (i = 0; i < 16; i++) {
|
||||
j = pos + i * 4;
|
||||
w[i] = (((p[j] & 0xff) << 24) | ((p[j + 1] & 0xff) << 16) |
|
||||
((p[j + 2] & 0xff) << 8) | (p[j + 3] & 0xff));
|
||||
}
|
||||
for (i = 16; i < 64; i++) {
|
||||
u = w[i - 2];
|
||||
t1 = (u >>> 17 | u << (32 - 17)) ^ (u >>> 19 | u << (32 - 19)) ^ (u >>> 10);
|
||||
u = w[i - 15];
|
||||
t2 = (u >>> 7 | u << (32 - 7)) ^ (u >>> 18 | u << (32 - 18)) ^ (u >>> 3);
|
||||
w[i] = (t1 + w[i - 7] | 0) + (t2 + w[i - 16] | 0);
|
||||
}
|
||||
for (i = 0; i < 64; i++) {
|
||||
t1 = (((((e >>> 6 | e << (32 - 6)) ^ (e >>> 11 | e << (32 - 11)) ^
|
||||
(e >>> 25 | e << (32 - 25))) + ((e & f) ^ (~e & g))) | 0) +
|
||||
((h + ((K[i] + w[i]) | 0)) | 0)) | 0;
|
||||
t2 = (((a >>> 2 | a << (32 - 2)) ^ (a >>> 13 | a << (32 - 13)) ^
|
||||
(a >>> 22 | a << (32 - 22))) + ((a & b) ^ (a & c) ^ (b & c))) | 0;
|
||||
h = g;
|
||||
g = f;
|
||||
f = e;
|
||||
e = (d + t1) | 0;
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
a = (t1 + t2) | 0;
|
||||
}
|
||||
v[0] += a;
|
||||
v[1] += b;
|
||||
v[2] += c;
|
||||
v[3] += d;
|
||||
v[4] += e;
|
||||
v[5] += f;
|
||||
v[6] += g;
|
||||
v[7] += h;
|
||||
pos += 64;
|
||||
len -= 64;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
// Hash implements SHA256 hash algorithm.
|
||||
var Hash = /** @class */ (function () {
|
||||
function Hash() {
|
||||
this.digestLength = exports.digestLength;
|
||||
this.blockSize = exports.blockSize;
|
||||
// Note: Int32Array is used instead of Uint32Array for performance reasons.
|
||||
this.state = new Int32Array(8); // hash state
|
||||
this.temp = new Int32Array(64); // temporary state
|
||||
this.buffer = new Uint8Array(128); // buffer for data to hash
|
||||
this.bufferLength = 0; // number of bytes in buffer
|
||||
this.bytesHashed = 0; // number of total bytes hashed
|
||||
this.finished = false; // indicates whether the hash was finalized
|
||||
this.reset();
|
||||
}
|
||||
// Resets hash state making it possible
|
||||
// to re-use this instance to hash other data.
|
||||
Hash.prototype.reset = function () {
|
||||
this.state[0] = 0x6a09e667;
|
||||
this.state[1] = 0xbb67ae85;
|
||||
this.state[2] = 0x3c6ef372;
|
||||
this.state[3] = 0xa54ff53a;
|
||||
this.state[4] = 0x510e527f;
|
||||
this.state[5] = 0x9b05688c;
|
||||
this.state[6] = 0x1f83d9ab;
|
||||
this.state[7] = 0x5be0cd19;
|
||||
this.bufferLength = 0;
|
||||
this.bytesHashed = 0;
|
||||
this.finished = false;
|
||||
return this;
|
||||
};
|
||||
// Cleans internal buffers and re-initializes hash state.
|
||||
Hash.prototype.clean = function () {
|
||||
for (var i = 0; i < this.buffer.length; i++) {
|
||||
this.buffer[i] = 0;
|
||||
}
|
||||
for (var i = 0; i < this.temp.length; i++) {
|
||||
this.temp[i] = 0;
|
||||
}
|
||||
this.reset();
|
||||
};
|
||||
// Updates hash state with the given data.
|
||||
//
|
||||
// Optionally, length of the data can be specified to hash
|
||||
// fewer bytes than data.length.
|
||||
//
|
||||
// Throws error when trying to update already finalized hash:
|
||||
// instance must be reset to use it again.
|
||||
Hash.prototype.update = function (data, dataLength) {
|
||||
if (dataLength === void 0) { dataLength = data.length; }
|
||||
if (this.finished) {
|
||||
throw new Error("SHA256: can't update because hash was finished.");
|
||||
}
|
||||
var dataPos = 0;
|
||||
this.bytesHashed += dataLength;
|
||||
if (this.bufferLength > 0) {
|
||||
while (this.bufferLength < 64 && dataLength > 0) {
|
||||
this.buffer[this.bufferLength++] = data[dataPos++];
|
||||
dataLength--;
|
||||
}
|
||||
if (this.bufferLength === 64) {
|
||||
hashBlocks(this.temp, this.state, this.buffer, 0, 64);
|
||||
this.bufferLength = 0;
|
||||
}
|
||||
}
|
||||
if (dataLength >= 64) {
|
||||
dataPos = hashBlocks(this.temp, this.state, data, dataPos, dataLength);
|
||||
dataLength %= 64;
|
||||
}
|
||||
while (dataLength > 0) {
|
||||
this.buffer[this.bufferLength++] = data[dataPos++];
|
||||
dataLength--;
|
||||
}
|
||||
return this;
|
||||
};
|
||||
// Finalizes hash state and puts hash into out.
|
||||
//
|
||||
// If hash was already finalized, puts the same value.
|
||||
Hash.prototype.finish = function (out) {
|
||||
if (!this.finished) {
|
||||
var bytesHashed = this.bytesHashed;
|
||||
var left = this.bufferLength;
|
||||
var bitLenHi = (bytesHashed / 0x20000000) | 0;
|
||||
var bitLenLo = bytesHashed << 3;
|
||||
var padLength = (bytesHashed % 64 < 56) ? 64 : 128;
|
||||
this.buffer[left] = 0x80;
|
||||
for (var i = left + 1; i < padLength - 8; i++) {
|
||||
this.buffer[i] = 0;
|
||||
}
|
||||
this.buffer[padLength - 8] = (bitLenHi >>> 24) & 0xff;
|
||||
this.buffer[padLength - 7] = (bitLenHi >>> 16) & 0xff;
|
||||
this.buffer[padLength - 6] = (bitLenHi >>> 8) & 0xff;
|
||||
this.buffer[padLength - 5] = (bitLenHi >>> 0) & 0xff;
|
||||
this.buffer[padLength - 4] = (bitLenLo >>> 24) & 0xff;
|
||||
this.buffer[padLength - 3] = (bitLenLo >>> 16) & 0xff;
|
||||
this.buffer[padLength - 2] = (bitLenLo >>> 8) & 0xff;
|
||||
this.buffer[padLength - 1] = (bitLenLo >>> 0) & 0xff;
|
||||
hashBlocks(this.temp, this.state, this.buffer, 0, padLength);
|
||||
this.finished = true;
|
||||
}
|
||||
for (var i = 0; i < 8; i++) {
|
||||
out[i * 4 + 0] = (this.state[i] >>> 24) & 0xff;
|
||||
out[i * 4 + 1] = (this.state[i] >>> 16) & 0xff;
|
||||
out[i * 4 + 2] = (this.state[i] >>> 8) & 0xff;
|
||||
out[i * 4 + 3] = (this.state[i] >>> 0) & 0xff;
|
||||
}
|
||||
return this;
|
||||
};
|
||||
// Returns the final hash digest.
|
||||
Hash.prototype.digest = function () {
|
||||
var out = new Uint8Array(this.digestLength);
|
||||
this.finish(out);
|
||||
return out;
|
||||
};
|
||||
// Internal function for use in HMAC for optimization.
|
||||
Hash.prototype._saveState = function (out) {
|
||||
for (var i = 0; i < this.state.length; i++) {
|
||||
out[i] = this.state[i];
|
||||
}
|
||||
};
|
||||
// Internal function for use in HMAC for optimization.
|
||||
Hash.prototype._restoreState = function (from, bytesHashed) {
|
||||
for (var i = 0; i < this.state.length; i++) {
|
||||
this.state[i] = from[i];
|
||||
}
|
||||
this.bytesHashed = bytesHashed;
|
||||
this.finished = false;
|
||||
this.bufferLength = 0;
|
||||
};
|
||||
return Hash;
|
||||
}());
|
||||
exports.Hash = Hash;
|
||||
// HMAC implements HMAC-SHA256 message authentication algorithm.
|
||||
var HMAC = /** @class */ (function () {
|
||||
function HMAC(key) {
|
||||
this.inner = new Hash();
|
||||
this.outer = new Hash();
|
||||
this.blockSize = this.inner.blockSize;
|
||||
this.digestLength = this.inner.digestLength;
|
||||
var pad = new Uint8Array(this.blockSize);
|
||||
if (key.length > this.blockSize) {
|
||||
(new Hash()).update(key).finish(pad).clean();
|
||||
}
|
||||
else {
|
||||
for (var i = 0; i < key.length; i++) {
|
||||
pad[i] = key[i];
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < pad.length; i++) {
|
||||
pad[i] ^= 0x36;
|
||||
}
|
||||
this.inner.update(pad);
|
||||
for (var i = 0; i < pad.length; i++) {
|
||||
pad[i] ^= 0x36 ^ 0x5c;
|
||||
}
|
||||
this.outer.update(pad);
|
||||
this.istate = new Uint32Array(8);
|
||||
this.ostate = new Uint32Array(8);
|
||||
this.inner._saveState(this.istate);
|
||||
this.outer._saveState(this.ostate);
|
||||
for (var i = 0; i < pad.length; i++) {
|
||||
pad[i] = 0;
|
||||
}
|
||||
}
|
||||
// Returns HMAC state to the state initialized with key
|
||||
// to make it possible to run HMAC over the other data with the same
|
||||
// key without creating a new instance.
|
||||
HMAC.prototype.reset = function () {
|
||||
this.inner._restoreState(this.istate, this.inner.blockSize);
|
||||
this.outer._restoreState(this.ostate, this.outer.blockSize);
|
||||
return this;
|
||||
};
|
||||
// Cleans HMAC state.
|
||||
HMAC.prototype.clean = function () {
|
||||
for (var i = 0; i < this.istate.length; i++) {
|
||||
this.ostate[i] = this.istate[i] = 0;
|
||||
}
|
||||
this.inner.clean();
|
||||
this.outer.clean();
|
||||
};
|
||||
// Updates state with provided data.
|
||||
HMAC.prototype.update = function (data) {
|
||||
this.inner.update(data);
|
||||
return this;
|
||||
};
|
||||
// Finalizes HMAC and puts the result in out.
|
||||
HMAC.prototype.finish = function (out) {
|
||||
if (this.outer.finished) {
|
||||
this.outer.finish(out);
|
||||
}
|
||||
else {
|
||||
this.inner.finish(out);
|
||||
this.outer.update(out, this.digestLength).finish(out);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
// Returns message authentication code.
|
||||
HMAC.prototype.digest = function () {
|
||||
var out = new Uint8Array(this.digestLength);
|
||||
this.finish(out);
|
||||
return out;
|
||||
};
|
||||
return HMAC;
|
||||
}());
|
||||
exports.HMAC = HMAC;
|
||||
// Returns SHA256 hash of data.
|
||||
function hash(data) {
|
||||
var h = (new Hash()).update(data);
|
||||
var digest = h.digest();
|
||||
h.clean();
|
||||
return digest;
|
||||
}
|
||||
exports.hash = hash;
|
||||
// Function hash is both available as module.hash and as default export.
|
||||
exports["default"] = hash;
|
||||
// Returns HMAC-SHA256 of data under the key.
|
||||
function hmac(key, data) {
|
||||
var h = (new HMAC(key)).update(data);
|
||||
var digest = h.digest();
|
||||
h.clean();
|
||||
return digest;
|
||||
}
|
||||
exports.hmac = hmac;
|
||||
// Fills hkdf buffer like this:
|
||||
// T(1) = HMAC-Hash(PRK, T(0) | info | 0x01)
|
||||
function fillBuffer(buffer, hmac, info, counter) {
|
||||
// Counter is a byte value: check if it overflowed.
|
||||
var num = counter[0];
|
||||
if (num === 0) {
|
||||
throw new Error("hkdf: cannot expand more");
|
||||
}
|
||||
// Prepare HMAC instance for new data with old key.
|
||||
hmac.reset();
|
||||
// Hash in previous output if it was generated
|
||||
// (i.e. counter is greater than 1).
|
||||
if (num > 1) {
|
||||
hmac.update(buffer);
|
||||
}
|
||||
// Hash in info if it exists.
|
||||
if (info) {
|
||||
hmac.update(info);
|
||||
}
|
||||
// Hash in the counter.
|
||||
hmac.update(counter);
|
||||
// Output result to buffer and clean HMAC instance.
|
||||
hmac.finish(buffer);
|
||||
// Increment counter inside typed array, this works properly.
|
||||
counter[0]++;
|
||||
}
|
||||
var hkdfSalt = new Uint8Array(exports.digestLength); // Filled with zeroes.
|
||||
function hkdf(key, salt, info, length) {
|
||||
if (salt === void 0) { salt = hkdfSalt; }
|
||||
if (length === void 0) { length = 32; }
|
||||
var counter = new Uint8Array([1]);
|
||||
// HKDF-Extract uses salt as HMAC key, and key as data.
|
||||
var okm = hmac(salt, key);
|
||||
// Initialize HMAC for expanding with extracted key.
|
||||
// Ensure no collisions with `hmac` function.
|
||||
var hmac_ = new HMAC(okm);
|
||||
// Allocate buffer.
|
||||
var buffer = new Uint8Array(hmac_.digestLength);
|
||||
var bufpos = buffer.length;
|
||||
var out = new Uint8Array(length);
|
||||
for (var i = 0; i < length; i++) {
|
||||
if (bufpos === buffer.length) {
|
||||
fillBuffer(buffer, hmac_, info, counter);
|
||||
bufpos = 0;
|
||||
}
|
||||
out[i] = buffer[bufpos++];
|
||||
}
|
||||
hmac_.clean();
|
||||
buffer.fill(0);
|
||||
counter.fill(0);
|
||||
return out;
|
||||
}
|
||||
exports.hkdf = hkdf;
|
||||
// Derives a key from password and salt using PBKDF2-HMAC-SHA256
|
||||
// with the given number of iterations.
|
||||
//
|
||||
// The number of bytes returned is equal to dkLen.
|
||||
//
|
||||
// (For better security, avoid dkLen greater than hash length - 32 bytes).
|
||||
function pbkdf2(password, salt, iterations, dkLen) {
|
||||
var prf = new HMAC(password);
|
||||
var len = prf.digestLength;
|
||||
var ctr = new Uint8Array(4);
|
||||
var t = new Uint8Array(len);
|
||||
var u = new Uint8Array(len);
|
||||
var dk = new Uint8Array(dkLen);
|
||||
for (var i = 0; i * len < dkLen; i++) {
|
||||
var c = i + 1;
|
||||
ctr[0] = (c >>> 24) & 0xff;
|
||||
ctr[1] = (c >>> 16) & 0xff;
|
||||
ctr[2] = (c >>> 8) & 0xff;
|
||||
ctr[3] = (c >>> 0) & 0xff;
|
||||
prf.reset();
|
||||
prf.update(salt);
|
||||
prf.update(ctr);
|
||||
prf.finish(u);
|
||||
for (var j = 0; j < len; j++) {
|
||||
t[j] = u[j];
|
||||
}
|
||||
for (var j = 2; j <= iterations; j++) {
|
||||
prf.reset();
|
||||
prf.update(u).finish(u);
|
||||
for (var k = 0; k < len; k++) {
|
||||
t[k] ^= u[k];
|
||||
}
|
||||
}
|
||||
for (var j = 0; j < len && i * len + j < dkLen; j++) {
|
||||
dk[i * len + j] = t[j];
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < len; i++) {
|
||||
t[i] = u[i] = 0;
|
||||
}
|
||||
for (var i = 0; i < 4; i++) {
|
||||
ctr[i] = 0;
|
||||
}
|
||||
prf.clean();
|
||||
return dk;
|
||||
}
|
||||
exports.pbkdf2 = pbkdf2;
|
||||
});
|
||||
852
core/third-party/math.js
vendored
Normal file
852
core/third-party/math.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2391
core/third-party/nacl-fast.js
vendored
Normal file
2391
core/third-party/nacl-fast.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2391
core/third-party/nacl-fast_orig.js
vendored
Normal file
2391
core/third-party/nacl-fast_orig.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
6373
core/third-party/pako.js
vendored
Normal file
6373
core/third-party/pako.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
153
core/third-party/pkijs/AccessDescription.js
vendored
Normal file
153
core/third-party/pkijs/AccessDescription.js
vendored
Normal file
@@ -0,0 +1,153 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import GeneralName from "./GeneralName.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5280
|
||||
*/
|
||||
export default class AccessDescription
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for AccessDescription class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {string}
|
||||
* @desc The type and format of the information are specified by the accessMethod field. This profile defines two accessMethod OIDs: id-ad-caIssuers and id-ad-ocsp
|
||||
*/
|
||||
this.accessMethod = getParametersValue(parameters, "accessMethod", AccessDescription.defaultValues("accessMethod"));
|
||||
/**
|
||||
* @type {GeneralName}
|
||||
* @desc The accessLocation field specifies the location of the information
|
||||
*/
|
||||
this.accessLocation = getParametersValue(parameters, "accessLocation", AccessDescription.defaultValues("accessLocation"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "accessMethod":
|
||||
return "";
|
||||
case "accessLocation":
|
||||
return new GeneralName();
|
||||
default:
|
||||
throw new Error(`Invalid member name for AccessDescription class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* AccessDescription ::= SEQUENCE {
|
||||
* accessMethod OBJECT IDENTIFIER,
|
||||
* accessLocation GeneralName }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [accessMethod]
|
||||
* @property {string} [accessLocation]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.ObjectIdentifier({ name: (names.accessMethod || "") }),
|
||||
GeneralName.schema(names.accessLocation || {})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"accessMethod",
|
||||
"accessLocation"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
AccessDescription.schema({
|
||||
names: {
|
||||
accessMethod: "accessMethod",
|
||||
accessLocation: {
|
||||
names: {
|
||||
blockName: "accessLocation"
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for AccessDescription");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.accessMethod = asn1.result.accessMethod.valueBlock.toString();
|
||||
this.accessLocation = new GeneralName({ schema: asn1.result.accessLocation });
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: [
|
||||
new asn1js.ObjectIdentifier({ value: this.accessMethod }),
|
||||
this.accessLocation.toSchema()
|
||||
]
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
return {
|
||||
accessMethod: this.accessMethod,
|
||||
accessLocation: this.accessLocation.toJSON()
|
||||
};
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
249
core/third-party/pkijs/Accuracy.js
vendored
Normal file
249
core/third-party/pkijs/Accuracy.js
vendored
Normal file
@@ -0,0 +1,249 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC3161. Accuracy represents the time deviation around the UTC time contained in GeneralizedTime.
|
||||
*/
|
||||
export default class Accuracy
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for Accuracy class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
if("seconds" in parameters)
|
||||
/**
|
||||
* @type {number}
|
||||
* @desc seconds
|
||||
*/
|
||||
this.seconds = getParametersValue(parameters, "seconds", Accuracy.defaultValues("seconds"));
|
||||
|
||||
if("millis" in parameters)
|
||||
/**
|
||||
* @type {number}
|
||||
* @desc millis
|
||||
*/
|
||||
this.millis = getParametersValue(parameters, "millis", Accuracy.defaultValues("millis"));
|
||||
|
||||
if("micros" in parameters)
|
||||
/**
|
||||
* @type {number}
|
||||
* @desc micros
|
||||
*/
|
||||
this.micros = getParametersValue(parameters, "micros", Accuracy.defaultValues("micros"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "seconds":
|
||||
case "millis":
|
||||
case "micros":
|
||||
return 0;
|
||||
default:
|
||||
throw new Error(`Invalid member name for Accuracy class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Compare values with default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
* @param {*} memberValue Value to compare with default value
|
||||
*/
|
||||
static compareWithDefault(memberName, memberValue)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "seconds":
|
||||
case "millis":
|
||||
case "micros":
|
||||
return (memberValue === Accuracy.defaultValues(memberName));
|
||||
default:
|
||||
throw new Error(`Invalid member name for Accuracy class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* Accuracy ::= SEQUENCE {
|
||||
* seconds INTEGER OPTIONAL,
|
||||
* millis [0] INTEGER (1..999) OPTIONAL,
|
||||
* micros [1] INTEGER (1..999) OPTIONAL }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [seconds]
|
||||
* @property {string} [millis]
|
||||
* @property {string} [micros]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
optional: true,
|
||||
value: [
|
||||
new asn1js.Integer({
|
||||
optional: true,
|
||||
name: (names.seconds || "")
|
||||
}),
|
||||
new asn1js.Primitive({
|
||||
name: (names.millis || ""),
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
}
|
||||
}),
|
||||
new asn1js.Primitive({
|
||||
name: (names.micros || ""),
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 1 // [1]
|
||||
}
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"seconds",
|
||||
"millis",
|
||||
"micros"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
Accuracy.schema({
|
||||
names: {
|
||||
seconds: "seconds",
|
||||
millis: "millis",
|
||||
micros: "micros"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for Accuracy");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
if("seconds" in asn1.result)
|
||||
this.seconds = asn1.result.seconds.valueBlock.valueDec;
|
||||
|
||||
if("millis" in asn1.result)
|
||||
{
|
||||
const intMillis = new asn1js.Integer({ valueHex: asn1.result.millis.valueBlock.valueHex });
|
||||
this.millis = intMillis.valueBlock.valueDec;
|
||||
}
|
||||
|
||||
if("micros" in asn1.result)
|
||||
{
|
||||
const intMicros = new asn1js.Integer({ valueHex: asn1.result.micros.valueBlock.valueHex });
|
||||
this.micros = intMicros.valueBlock.valueDec;
|
||||
}
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Create array of output sequence
|
||||
const outputArray = [];
|
||||
|
||||
if("seconds" in this)
|
||||
outputArray.push(new asn1js.Integer({ value: this.seconds }));
|
||||
|
||||
if("millis" in this)
|
||||
{
|
||||
const intMillis = new asn1js.Integer({ value: this.millis });
|
||||
|
||||
outputArray.push(new asn1js.Primitive({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
valueHex: intMillis.valueBlock.valueHex
|
||||
}));
|
||||
}
|
||||
|
||||
if("micros" in this)
|
||||
{
|
||||
const intMicros = new asn1js.Integer({ value: this.micros });
|
||||
|
||||
outputArray.push(new asn1js.Primitive({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 1 // [1]
|
||||
},
|
||||
valueHex: intMicros.valueBlock.valueHex
|
||||
}));
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: outputArray
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
const _object = {};
|
||||
|
||||
if("seconds" in this)
|
||||
_object.seconds = this.seconds;
|
||||
|
||||
if("millis" in this)
|
||||
_object.millis = this.millis;
|
||||
|
||||
if("micros" in this)
|
||||
_object.micros = this.micros;
|
||||
|
||||
return _object;
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
212
core/third-party/pkijs/AlgorithmIdentifier.js
vendored
Normal file
212
core/third-party/pkijs/AlgorithmIdentifier.js
vendored
Normal file
@@ -0,0 +1,212 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5280
|
||||
*/
|
||||
export default class AlgorithmIdentifier
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for AlgorithmIdentifier class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
* @property {string} [algorithmId] ObjectIdentifier for algorithm (string representation)
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {string}
|
||||
* @desc ObjectIdentifier for algorithm (string representation)
|
||||
*/
|
||||
this.algorithmId = getParametersValue(parameters, "algorithmId", AlgorithmIdentifier.defaultValues("algorithmId"));
|
||||
|
||||
if("algorithmParams" in parameters)
|
||||
/**
|
||||
* @type {Object}
|
||||
* @desc Any algorithm parameters
|
||||
*/
|
||||
this.algorithmParams = getParametersValue(parameters, "algorithmParams", AlgorithmIdentifier.defaultValues("algorithmParams"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "algorithmId":
|
||||
return "";
|
||||
case "algorithmParams":
|
||||
return new asn1js.Any();
|
||||
default:
|
||||
throw new Error(`Invalid member name for AlgorithmIdentifier class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Compare values with default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
* @param {*} memberValue Value to compare with default value
|
||||
*/
|
||||
static compareWithDefault(memberName, memberValue)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "algorithmId":
|
||||
return (memberValue === "");
|
||||
case "algorithmParams":
|
||||
return (memberValue instanceof asn1js.Any);
|
||||
default:
|
||||
throw new Error(`Invalid member name for AlgorithmIdentifier class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* AlgorithmIdentifier ::= Sequence {
|
||||
* algorithm OBJECT IDENTIFIER,
|
||||
* parameters ANY DEFINED BY algorithm OPTIONAL }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} algorithmIdentifier ObjectIdentifier for the algorithm
|
||||
* @property {string} algorithmParams Any algorithm parameters
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
optional: (names.optional || false),
|
||||
value: [
|
||||
new asn1js.ObjectIdentifier({ name: (names.algorithmIdentifier || "") }),
|
||||
new asn1js.Any({ name: (names.algorithmParams || ""), optional: true })
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"algorithm",
|
||||
"params"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
AlgorithmIdentifier.schema({
|
||||
names: {
|
||||
algorithmIdentifier: "algorithm",
|
||||
algorithmParams: "params"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for AlgorithmIdentifier");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.algorithmId = asn1.result.algorithm.valueBlock.toString();
|
||||
if("params" in asn1.result)
|
||||
this.algorithmParams = asn1.result.params;
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Create array for output sequence
|
||||
const outputArray = [];
|
||||
|
||||
outputArray.push(new asn1js.ObjectIdentifier({ value: this.algorithmId }));
|
||||
if(("algorithmParams" in this) && ((this.algorithmParams instanceof asn1js.Any) === false))
|
||||
outputArray.push(this.algorithmParams);
|
||||
//endregion
|
||||
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: outputArray
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
const object = {
|
||||
algorithmId: this.algorithmId
|
||||
};
|
||||
|
||||
if(("algorithmParams" in this) && ((this.algorithmParams instanceof asn1js.Any) === false))
|
||||
object.algorithmParams = this.algorithmParams.toJSON();
|
||||
|
||||
return object;
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Check that two "AlgorithmIdentifiers" are equal
|
||||
* @param {AlgorithmIdentifier} algorithmIdentifier
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isEqual(algorithmIdentifier)
|
||||
{
|
||||
//region Check input type
|
||||
if((algorithmIdentifier instanceof AlgorithmIdentifier) === false)
|
||||
return false;
|
||||
//endregion
|
||||
|
||||
//region Check "algorithm_id"
|
||||
if(this.algorithmId !== algorithmIdentifier.algorithmId)
|
||||
return false;
|
||||
//endregion
|
||||
|
||||
//region Check "algorithm_params"
|
||||
if("algorithmParams" in this)
|
||||
{
|
||||
if("algorithmParams" in algorithmIdentifier)
|
||||
return JSON.stringify(this.algorithmParams) === JSON.stringify(algorithmIdentifier.algorithmParams);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if("algorithmParams" in algorithmIdentifier)
|
||||
return false;
|
||||
//endregion
|
||||
|
||||
return true;
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
135
core/third-party/pkijs/AltName.js
vendored
Normal file
135
core/third-party/pkijs/AltName.js
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import GeneralName from "./GeneralName.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5280
|
||||
*/
|
||||
export default class AltName
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for AltName class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {Array.<GeneralName>}
|
||||
* @desc Array of alternative names in GeneralName type
|
||||
*/
|
||||
this.altNames = getParametersValue(parameters, "altNames", AltName.defaultValues("altNames"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "altNames":
|
||||
return [];
|
||||
default:
|
||||
throw new Error(`Invalid member name for AltName class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* AltName ::= GeneralNames
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [altNames]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.Repeated({
|
||||
name: (names.altNames || ""),
|
||||
value: GeneralName.schema()
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"altNames"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
AltName.schema({
|
||||
names: {
|
||||
altNames: "altNames"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for AltName");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
if("altNames" in asn1.result)
|
||||
this.altNames = Array.from(asn1.result.altNames, element => new GeneralName({ schema: element }));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: Array.from(this.altNames, element => element.toSchema())
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
return {
|
||||
altNames: Array.from(this.altNames, element => element.toJSON())
|
||||
};
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
177
core/third-party/pkijs/Attribute.js
vendored
Normal file
177
core/third-party/pkijs/Attribute.js
vendored
Normal file
@@ -0,0 +1,177 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC2986
|
||||
*/
|
||||
export default class Attribute {
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for Attribute class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {string}
|
||||
* @desc ObjectIdentifier for attribute (string representation)
|
||||
*/
|
||||
this.type = getParametersValue(parameters, "type", Attribute.defaultValues("type"));
|
||||
/**
|
||||
* @type {Array}
|
||||
* @desc Any attribute values
|
||||
*/
|
||||
this.values = getParametersValue(parameters, "values", Attribute.defaultValues("values"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "type":
|
||||
return "";
|
||||
case "values":
|
||||
return [];
|
||||
default:
|
||||
throw new Error(`Invalid member name for Attribute class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Compare values with default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
* @param {*} memberValue Value to compare with default value
|
||||
*/
|
||||
static compareWithDefault(memberName, memberValue)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "type":
|
||||
return (memberValue === "");
|
||||
case "values":
|
||||
return (memberValue.length === 0);
|
||||
default:
|
||||
throw new Error(`Invalid member name for Attribute class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* Attribute { ATTRIBUTE:IOSet } ::= SEQUENCE {
|
||||
* type ATTRIBUTE.&id({IOSet}),
|
||||
* values SET SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{@type})
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [type]
|
||||
* @property {string} [setName]
|
||||
* @property {string} [values]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.ObjectIdentifier({ name: (names.type || "") }),
|
||||
new asn1js.Set({
|
||||
name: (names.setName || ""),
|
||||
value: [
|
||||
new asn1js.Repeated({
|
||||
name: (names.values || ""),
|
||||
value: new asn1js.Any()
|
||||
})
|
||||
]
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"type",
|
||||
"values"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
Attribute.schema({
|
||||
names: {
|
||||
type: "type",
|
||||
values: "values"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for Attribute");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.type = asn1.result.type.valueBlock.toString();
|
||||
this.values = asn1.result.values;
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: [
|
||||
new asn1js.ObjectIdentifier({ value: this.type }),
|
||||
new asn1js.Set({
|
||||
value: this.values
|
||||
})
|
||||
]
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
return {
|
||||
type: this.type,
|
||||
values: Array.from(this.values, element => element.toJSON())
|
||||
};
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
871
core/third-party/pkijs/AttributeCertificateV1.js
vendored
Normal file
871
core/third-party/pkijs/AttributeCertificateV1.js
vendored
Normal file
@@ -0,0 +1,871 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import GeneralNames from "./GeneralNames.js";
|
||||
import AlgorithmIdentifier from "./AlgorithmIdentifier.js";
|
||||
import Attribute from "./Attribute.js";
|
||||
import Extensions from "./Extensions.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5755
|
||||
*/
|
||||
export class AttCertValidityPeriod
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for AttCertValidityPeriod class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {GeneralizedTime}
|
||||
* @desc notBeforeTime
|
||||
*/
|
||||
this.notBeforeTime = getParametersValue(parameters, "notBeforeTime", AttCertValidityPeriod.defaultValues("notBeforeTime"));
|
||||
/**
|
||||
* @type {GeneralizedTime}
|
||||
* @desc notAfterTime
|
||||
*/
|
||||
this.notAfterTime = getParametersValue(parameters, "notAfterTime", AttCertValidityPeriod.defaultValues("notAfterTime"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "notBeforeTime":
|
||||
case "notAfterTime":
|
||||
return new Date(0, 0, 0);
|
||||
default:
|
||||
throw new Error(`Invalid member name for AttCertValidityPeriod class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* AttCertValidityPeriod ::= SEQUENCE {
|
||||
* notBeforeTime GeneralizedTime,
|
||||
* notAfterTime GeneralizedTime
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [notBeforeTime]
|
||||
* @property {string} [notAfterTime]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.GeneralizedTime({ name: (names.notBeforeTime || "") }),
|
||||
new asn1js.GeneralizedTime({ name: (names.notAfterTime || "") })
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"notBeforeTime",
|
||||
"notAfterTime"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
AttCertValidityPeriod.schema({
|
||||
names: {
|
||||
notBeforeTime: "notBeforeTime",
|
||||
notAfterTime: "notAfterTime"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for AttCertValidityPeriod");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.notBeforeTime = asn1.result.notBeforeTime.toDate();
|
||||
this.notAfterTime = asn1.result.notAfterTime.toDate();
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: [
|
||||
new asn1js.GeneralizedTime({ valueDate: this.notBeforeTime }),
|
||||
new asn1js.GeneralizedTime({ valueDate: this.notAfterTime }),
|
||||
]
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
return {
|
||||
notBeforeTime: this.notBeforeTime,
|
||||
notAfterTime: this.notAfterTime
|
||||
};
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5755
|
||||
*/
|
||||
export class IssuerSerial
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for IssuerSerial class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {RelativeDistinguishedNames}
|
||||
* @desc issuer
|
||||
*/
|
||||
this.issuer = getParametersValue(parameters, "issuer", IssuerSerial.defaultValues("issuer"));
|
||||
/**
|
||||
* @type {Integer}
|
||||
* @desc serialNumber
|
||||
*/
|
||||
this.serialNumber = getParametersValue(parameters, "serialNumber", IssuerSerial.defaultValues("serialNumber"));
|
||||
|
||||
if("issuerUID" in parameters)
|
||||
/**
|
||||
* @type {BitString}
|
||||
* @desc issuerUID
|
||||
*/
|
||||
this.issuerUID = getParametersValue(parameters, "issuerUID", IssuerSerial.defaultValues("issuerUID"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "issuer":
|
||||
return new GeneralNames();
|
||||
case "serialNumber":
|
||||
return new asn1js.Integer();
|
||||
case "issuerUID":
|
||||
return new asn1js.BitString();
|
||||
default:
|
||||
throw new Error(`Invalid member name for IssuerSerial class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* IssuerSerial ::= SEQUENCE {
|
||||
* issuer GeneralNames,
|
||||
* serial CertificateSerialNumber,
|
||||
* issuerUID UniqueIdentifier OPTIONAL
|
||||
* }
|
||||
*
|
||||
* CertificateSerialNumber ::= INTEGER
|
||||
* UniqueIdentifier ::= BIT STRING
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [issuer]
|
||||
* @property {string} [serialNumber]
|
||||
* @property {string} [issuerUID]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
GeneralNames.schema(names.issuer || {}),
|
||||
new asn1js.Integer({ name: (names.serialNumber || "") }),
|
||||
new asn1js.BitString({
|
||||
optional: true,
|
||||
name: (names.issuerUID || "")
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"issuer",
|
||||
"serialNumber",
|
||||
"issuerUID"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
IssuerSerial.schema({
|
||||
names: {
|
||||
issuer: {
|
||||
names: {
|
||||
blockName: "issuer"
|
||||
}
|
||||
},
|
||||
serialNumber: "serialNumber",
|
||||
issuerUID: "issuerUID"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for IssuerSerial");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.issuer = new GeneralNames({ schema: asn1.result.issuer });
|
||||
this.serialNumber = asn1.result.serialNumber;
|
||||
|
||||
if("issuerUID" in asn1.result)
|
||||
this.issuerUID = asn1.result.issuerUID;
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
const result = new asn1js.Sequence({
|
||||
value: [
|
||||
this.issuer.toSchema(),
|
||||
this.serialNumber
|
||||
]
|
||||
});
|
||||
|
||||
if("issuerUID" in this)
|
||||
result.valueBlock.value.push(this.issuerUID);
|
||||
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return result;
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
const result = {
|
||||
issuer: this.issuer.toJSON(),
|
||||
serialNumber: this.serialNumber.toJSON()
|
||||
};
|
||||
|
||||
if("issuerUID" in this)
|
||||
result.issuerUID = this.issuerUID.toJSON();
|
||||
|
||||
return result;
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5755
|
||||
*/
|
||||
export class AttributeCertificateInfoV1
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for AttributeCertificateInfoV1 class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {Number}
|
||||
* @desc version
|
||||
*/
|
||||
this.version = getParametersValue(parameters, "version", AttributeCertificateInfoV1.defaultValues("version"));
|
||||
|
||||
if("baseCertificateID" in parameters)
|
||||
/**
|
||||
* @type {IssuerSerial}
|
||||
* @desc baseCertificateID
|
||||
*/
|
||||
this.baseCertificateID = getParametersValue(parameters, "baseCertificateID", AttributeCertificateInfoV1.defaultValues("baseCertificateID"));
|
||||
|
||||
if("subjectName" in parameters)
|
||||
/**
|
||||
* @type {GeneralNames}
|
||||
* @desc subjectName
|
||||
*/
|
||||
this.subjectName = getParametersValue(parameters, "subjectName", AttributeCertificateInfoV1.defaultValues("subjectName"));
|
||||
|
||||
/**
|
||||
* @type {GeneralNames}
|
||||
* @desc issuer
|
||||
*/
|
||||
this.issuer = getParametersValue(parameters, "issuer", AttributeCertificateInfoV1.defaultValues("issuer"));
|
||||
/**
|
||||
* @type {AlgorithmIdentifier}
|
||||
* @desc signature
|
||||
*/
|
||||
this.signature = getParametersValue(parameters, "signature", AttributeCertificateInfoV1.defaultValues("signature"));
|
||||
/**
|
||||
* @type {Integer}
|
||||
* @desc serialNumber
|
||||
*/
|
||||
this.serialNumber = getParametersValue(parameters, "serialNumber", AttributeCertificateInfoV1.defaultValues("serialNumber"));
|
||||
/**
|
||||
* @type {AttCertValidityPeriod}
|
||||
* @desc attrCertValidityPeriod
|
||||
*/
|
||||
this.attrCertValidityPeriod = getParametersValue(parameters, "attrCertValidityPeriod", AttributeCertificateInfoV1.defaultValues("attrCertValidityPeriod"));
|
||||
/**
|
||||
* @type {Array.<Attribute>}
|
||||
* @desc attributes
|
||||
*/
|
||||
this.attributes = getParametersValue(parameters, "attributes", AttributeCertificateInfoV1.defaultValues("attributes"));
|
||||
|
||||
if("issuerUniqueID" in parameters)
|
||||
/**
|
||||
* @type {BitString}
|
||||
* @desc issuerUniqueID
|
||||
*/
|
||||
this.issuerUniqueID = getParametersValue(parameters, "issuerUniqueID", AttributeCertificateInfoV1.defaultValues("issuerUniqueID"));
|
||||
|
||||
if("extensions" in parameters)
|
||||
/**
|
||||
* @type {Extensions}
|
||||
* @desc extensions
|
||||
*/
|
||||
this.extensions = getParametersValue(parameters, "extensions", AttributeCertificateInfoV1.defaultValues("extensions"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "version":
|
||||
return 0;
|
||||
case "baseCertificateID":
|
||||
return new IssuerSerial();
|
||||
case "subjectName":
|
||||
return new GeneralNames();
|
||||
case "issuer":
|
||||
return {};
|
||||
case "signature":
|
||||
return new AlgorithmIdentifier();
|
||||
case "serialNumber":
|
||||
return new asn1js.Integer();
|
||||
case "attrCertValidityPeriod":
|
||||
return new AttCertValidityPeriod();
|
||||
case "attributes":
|
||||
return [];
|
||||
case "issuerUniqueID":
|
||||
return new asn1js.BitString();
|
||||
case "extensions":
|
||||
return new Extensions();
|
||||
default:
|
||||
throw new Error(`Invalid member name for AttributeCertificateInfoV1 class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* AttributeCertificateInfo ::= SEQUENCE {
|
||||
* version Version DEFAULT v1,
|
||||
* subject CHOICE {
|
||||
* baseCertificateID [0] IssuerSerial, -- associated with a Public Key Certificate
|
||||
* subjectName [1] GeneralNames }, -- associated with a name
|
||||
* issuer GeneralNames, -- CA issuing the attribute certificate
|
||||
* signature AlgorithmIdentifier,
|
||||
* serialNumber CertificateSerialNumber,
|
||||
* attrCertValidityPeriod AttCertValidityPeriod,
|
||||
* attributes SEQUENCE OF Attribute,
|
||||
* issuerUniqueID UniqueIdentifier OPTIONAL,
|
||||
* extensions Extensions OPTIONAL
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [issuer]
|
||||
* @property {string} [serialNumber]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.Integer({ name: (names.version || "") }),
|
||||
new asn1js.Choice({
|
||||
value: [
|
||||
new asn1js.Constructed({
|
||||
name: (names.baseCertificateID || ""),
|
||||
idBlock: {
|
||||
tagClass: 3,
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: IssuerSerial.schema().valueBlock.value
|
||||
}),
|
||||
new asn1js.Constructed({
|
||||
name: (names.subjectName || ""),
|
||||
idBlock: {
|
||||
tagClass: 3,
|
||||
tagNumber: 1 // [2]
|
||||
},
|
||||
value: GeneralNames.schema().valueBlock.value
|
||||
}),
|
||||
]
|
||||
}),
|
||||
GeneralNames.schema({
|
||||
names: {
|
||||
blockName: (names.issuer || "")
|
||||
}
|
||||
}),
|
||||
AlgorithmIdentifier.schema(names.signature || {}),
|
||||
new asn1js.Integer({ name: (names.serialNumber || "") }),
|
||||
AttCertValidityPeriod.schema(names.attrCertValidityPeriod || {}),
|
||||
new asn1js.Sequence({
|
||||
name: (names.attributes || ""),
|
||||
value: [
|
||||
new asn1js.Repeated({
|
||||
value: Attribute.schema()
|
||||
})
|
||||
]
|
||||
}),
|
||||
new asn1js.BitString({
|
||||
optional: true,
|
||||
name: (names.issuerUniqueID || "")
|
||||
}),
|
||||
Extensions.schema(names.extensions || {}, true)
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"version",
|
||||
"baseCertificateID",
|
||||
"subjectName",
|
||||
"issuer",
|
||||
"signature",
|
||||
"serialNumber",
|
||||
"attrCertValidityPeriod",
|
||||
"attributes",
|
||||
"issuerUniqueID",
|
||||
"extensions"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
AttributeCertificateInfoV1.schema({
|
||||
names: {
|
||||
version: "version",
|
||||
baseCertificateID: "baseCertificateID",
|
||||
subjectName: "subjectName",
|
||||
issuer: "issuer",
|
||||
signature: {
|
||||
names: {
|
||||
blockName: "signature"
|
||||
}
|
||||
},
|
||||
serialNumber: "serialNumber",
|
||||
attrCertValidityPeriod: {
|
||||
names: {
|
||||
blockName: "attrCertValidityPeriod"
|
||||
}
|
||||
},
|
||||
attributes: "attributes",
|
||||
issuerUniqueID: "issuerUniqueID",
|
||||
extensions: {
|
||||
names: {
|
||||
blockName: "extensions"
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for AttributeCertificateInfoV1");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.version = asn1.result.version.valueBlock.valueDec;
|
||||
|
||||
if("baseCertificateID" in asn1.result)
|
||||
{
|
||||
this.baseCertificateID = new IssuerSerial({
|
||||
schema: new asn1js.Sequence({
|
||||
value: asn1.result.baseCertificateID.valueBlock.value
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
if("subjectName" in asn1.result)
|
||||
{
|
||||
this.subjectName = new GeneralNames({
|
||||
schema: new asn1js.Sequence({
|
||||
value: asn1.result.subjectName.valueBlock.value
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
this.issuer = asn1.result.issuer;
|
||||
this.signature = new AlgorithmIdentifier({ schema: asn1.result.signature });
|
||||
this.serialNumber = asn1.result.serialNumber;
|
||||
this.attrCertValidityPeriod = new AttCertValidityPeriod({ schema: asn1.result.attrCertValidityPeriod });
|
||||
this.attributes = Array.from(asn1.result.attributes.valueBlock.value, element => new Attribute({ schema: element }));
|
||||
|
||||
if("issuerUniqueID" in asn1.result)
|
||||
this.issuerUniqueID = asn1.result.issuerUniqueID;
|
||||
|
||||
if("extensions" in asn1.result)
|
||||
this.extensions = new Extensions({ schema: asn1.result.extensions });
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
const result = new asn1js.Sequence({
|
||||
value: [new asn1js.Integer({ value: this.version })]
|
||||
});
|
||||
|
||||
if("baseCertificateID" in this)
|
||||
{
|
||||
result.valueBlock.value.push(new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3,
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: this.baseCertificateID.toSchema().valueBlock.value
|
||||
}));
|
||||
}
|
||||
|
||||
if("subjectName" in this)
|
||||
{
|
||||
result.valueBlock.value.push(new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3,
|
||||
tagNumber: 1 // [1]
|
||||
},
|
||||
value: this.subjectName.toSchema().valueBlock.value
|
||||
}));
|
||||
}
|
||||
|
||||
result.valueBlock.value.push(this.issuer.toSchema());
|
||||
result.valueBlock.value.push(this.signature.toSchema());
|
||||
result.valueBlock.value.push(this.serialNumber);
|
||||
result.valueBlock.value.push(this.attrCertValidityPeriod.toSchema());
|
||||
result.valueBlock.value.push(new asn1js.Sequence({
|
||||
value: Array.from(this.attributes, element => element.toSchema())
|
||||
}));
|
||||
|
||||
if("issuerUniqueID" in this)
|
||||
result.valueBlock.value.push(this.issuerUniqueID);
|
||||
|
||||
if("extensions" in this)
|
||||
result.valueBlock.value.push(this.extensions.toSchema());
|
||||
|
||||
return result;
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
const result = {
|
||||
version: this.version
|
||||
};
|
||||
|
||||
if("baseCertificateID" in this)
|
||||
result.baseCertificateID = this.baseCertificateID.toJSON();
|
||||
|
||||
if("subjectName" in this)
|
||||
result.subjectName = this.subjectName.toJSON();
|
||||
|
||||
result.issuer = this.issuer.toJSON();
|
||||
result.signature = this.signature.toJSON();
|
||||
result.serialNumber = this.serialNumber.toJSON();
|
||||
result.attrCertValidityPeriod = this.attrCertValidityPeriod.toJSON();
|
||||
result.attributes = Array.from(this.attributes, element => element.toJSON());
|
||||
|
||||
if("issuerUniqueID" in this)
|
||||
result.issuerUniqueID = this.issuerUniqueID.toJSON();
|
||||
|
||||
if("extensions" in this)
|
||||
result.extensions = this.extensions.toJSON();
|
||||
|
||||
return result;
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from X.509:1997
|
||||
*/
|
||||
export default class AttributeCertificateV1
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for AttributeCertificateV1 class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {AttributeCertificateInfoV1}
|
||||
* @desc acinfo
|
||||
*/
|
||||
this.acinfo = getParametersValue(parameters, "acinfo", AttributeCertificateV1.defaultValues("acinfo"));
|
||||
/**
|
||||
* @type {AlgorithmIdentifier}
|
||||
* @desc signatureAlgorithm
|
||||
*/
|
||||
this.signatureAlgorithm = getParametersValue(parameters, "signatureAlgorithm", AttributeCertificateV1.defaultValues("signatureAlgorithm"));
|
||||
/**
|
||||
* @type {BitString}
|
||||
* @desc signatureValue
|
||||
*/
|
||||
this.signatureValue = getParametersValue(parameters, "signatureValue", AttributeCertificateV1.defaultValues("signatureValue"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "acinfo":
|
||||
return new AttributeCertificateInfoV1();
|
||||
case "signatureAlgorithm":
|
||||
return new AlgorithmIdentifier();
|
||||
case "signatureValue":
|
||||
return new asn1js.BitString();
|
||||
default:
|
||||
throw new Error(`Invalid member name for AttributeCertificateV1 class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* AttributeCertificate ::= SEQUENCE {
|
||||
* acinfo AttributeCertificateInfoV1,
|
||||
* signatureAlgorithm AlgorithmIdentifier,
|
||||
* signatureValue BIT STRING
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {Object} [acinfo]
|
||||
* @property {Object} [signatureAlgorithm]
|
||||
* @property {string} [signatureValue]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
AttributeCertificateInfoV1.schema(names.acinfo || {}),
|
||||
AlgorithmIdentifier.schema(names.signatureAlgorithm || {}),
|
||||
new asn1js.BitString({ name: (names.signatureValue || "") })
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"acinfo",
|
||||
"signatureValue",
|
||||
"signatureAlgorithm"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
AttributeCertificateV1.schema({
|
||||
names: {
|
||||
acinfo: {
|
||||
names: {
|
||||
blockName: "acinfo"
|
||||
}
|
||||
},
|
||||
signatureAlgorithm: {
|
||||
names: {
|
||||
blockName: "signatureAlgorithm"
|
||||
}
|
||||
},
|
||||
signatureValue: "signatureValue"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for AttributeCertificateV1");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.acinfo = new AttributeCertificateInfoV1({ schema: asn1.result.acinfo });
|
||||
this.signatureAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.signatureAlgorithm });
|
||||
this.signatureValue = asn1.result.signatureValue;
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
return (new asn1js.Sequence({
|
||||
value: [
|
||||
this.acinfo.toSchema(),
|
||||
this.signatureAlgorithm.toSchema(),
|
||||
this.signatureValue
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
return {
|
||||
acinfo: this.acinfo.toJSON(),
|
||||
signatureAlgorithm: this.signatureAlgorithm.toJSON(),
|
||||
signatureValue: this.signatureValue.toJSON()
|
||||
};
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
1187
core/third-party/pkijs/AttributeCertificateV2.js
vendored
Normal file
1187
core/third-party/pkijs/AttributeCertificateV2.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
232
core/third-party/pkijs/AttributeTypeAndValue.js
vendored
Normal file
232
core/third-party/pkijs/AttributeTypeAndValue.js
vendored
Normal file
@@ -0,0 +1,232 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, isEqualBuffer, clearProps } from "./pvutils.js";
|
||||
import { stringPrep } from "./common.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5280
|
||||
*/
|
||||
export default class AttributeTypeAndValue
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for AttributeTypeAndValue class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {string}
|
||||
* @desc type
|
||||
*/
|
||||
this.type = getParametersValue(parameters, "type", AttributeTypeAndValue.defaultValues("type"));
|
||||
/**
|
||||
* @type {Object}
|
||||
* @desc Value of the AttributeTypeAndValue class
|
||||
*/
|
||||
this.value = getParametersValue(parameters, "value", AttributeTypeAndValue.defaultValues("value"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "type":
|
||||
return "";
|
||||
case "value":
|
||||
return {};
|
||||
default:
|
||||
throw new Error(`Invalid member name for AttributeTypeAndValue class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* AttributeTypeAndValue ::= Sequence {
|
||||
* type AttributeType,
|
||||
* value AttributeValue }
|
||||
*
|
||||
* AttributeType ::= OBJECT IDENTIFIER
|
||||
*
|
||||
* AttributeValue ::= ANY -- DEFINED BY AttributeType
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName] Name for entire block
|
||||
* @property {string} [type] Name for "type" element
|
||||
* @property {string} [value] Name for "value" element
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.ObjectIdentifier({ name: (names.type || "") }),
|
||||
new asn1js.Any({ name: (names.value || "") })
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
static blockName()
|
||||
{
|
||||
return "AttributeTypeAndValue";
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"type",
|
||||
"typeValue"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
AttributeTypeAndValue.schema({
|
||||
names: {
|
||||
type: "type",
|
||||
value: "typeValue"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for AttributeTypeAndValue");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.type = asn1.result.type.valueBlock.toString();
|
||||
// noinspection JSUnresolvedVariable
|
||||
this.value = asn1.result.typeValue;
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: [
|
||||
new asn1js.ObjectIdentifier({ value: this.type }),
|
||||
this.value
|
||||
]
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
const _object = {
|
||||
type: this.type
|
||||
};
|
||||
|
||||
if(Object.keys(this.value).length !== 0)
|
||||
_object.value = this.value.toJSON();
|
||||
else
|
||||
_object.value = this.value;
|
||||
|
||||
return _object;
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Compare two AttributeTypeAndValue values, or AttributeTypeAndValue with ArrayBuffer value
|
||||
* @param {(AttributeTypeAndValue|ArrayBuffer)} compareTo The value compare to current
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isEqual(compareTo)
|
||||
{
|
||||
const stringBlockNames = [
|
||||
asn1js.Utf8String.blockName(),
|
||||
asn1js.BmpString.blockName(),
|
||||
asn1js.UniversalString.blockName(),
|
||||
asn1js.NumericString.blockName(),
|
||||
asn1js.PrintableString.blockName(),
|
||||
asn1js.TeletexString.blockName(),
|
||||
asn1js.VideotexString.blockName(),
|
||||
asn1js.IA5String.blockName(),
|
||||
asn1js.GraphicString.blockName(),
|
||||
asn1js.VisibleString.blockName(),
|
||||
asn1js.GeneralString.blockName(),
|
||||
asn1js.CharacterString.blockName()
|
||||
];
|
||||
|
||||
if(compareTo.constructor.blockName() === AttributeTypeAndValue.blockName())
|
||||
{
|
||||
if(this.type !== compareTo.type)
|
||||
return false;
|
||||
|
||||
//region Check we do have both strings
|
||||
let isString = false;
|
||||
const thisName = this.value.constructor.blockName();
|
||||
|
||||
if(thisName === compareTo.value.constructor.blockName())
|
||||
{
|
||||
for(const name of stringBlockNames)
|
||||
{
|
||||
if(thisName === name)
|
||||
{
|
||||
isString = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//endregion
|
||||
|
||||
if(isString)
|
||||
{
|
||||
const value1 = stringPrep(this.value.valueBlock.value);
|
||||
const value2 = stringPrep(compareTo.value.valueBlock.value);
|
||||
|
||||
if(value1.localeCompare(value2) !== 0)
|
||||
return false;
|
||||
}
|
||||
else // Comparing as two ArrayBuffers
|
||||
{
|
||||
if(isEqualBuffer(this.value.valueBeforeDecode, compareTo.value.valueBeforeDecode) === false)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if(compareTo instanceof ArrayBuffer)
|
||||
return isEqualBuffer(this.value.valueBeforeDecode, compareTo);
|
||||
|
||||
return false;
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
513
core/third-party/pkijs/AuthenticatedSafe.js
vendored
Normal file
513
core/third-party/pkijs/AuthenticatedSafe.js
vendored
Normal file
@@ -0,0 +1,513 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, utilConcatBuf, clearProps } from "./pvutils.js";
|
||||
import ContentInfo from "./ContentInfo.js";
|
||||
import SafeContents from "./SafeContents.js";
|
||||
import EnvelopedData from "./EnvelopedData.js";
|
||||
import EncryptedData from "./EncryptedData.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC7292
|
||||
*/
|
||||
export default class AuthenticatedSafe
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for AuthenticatedSafe class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {Array.<ContentInfo>}
|
||||
* @desc safeContents
|
||||
*/
|
||||
this.safeContents = getParametersValue(parameters, "safeContents", AuthenticatedSafe.defaultValues("safeContents"));
|
||||
|
||||
if("parsedValue" in parameters)
|
||||
/**
|
||||
* @type {*}
|
||||
* @desc parsedValue
|
||||
*/
|
||||
this.parsedValue = getParametersValue(parameters, "parsedValue", AuthenticatedSafe.defaultValues("parsedValue"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "safeContents":
|
||||
return [];
|
||||
case "parsedValue":
|
||||
return {};
|
||||
default:
|
||||
throw new Error(`Invalid member name for AuthenticatedSafe class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Compare values with default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
* @param {*} memberValue Value to compare with default value
|
||||
*/
|
||||
static compareWithDefault(memberName, memberValue)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "safeContents":
|
||||
return (memberValue.length === 0);
|
||||
case "parsedValue":
|
||||
return ((memberValue instanceof Object) && (Object.keys(memberValue).length === 0));
|
||||
default:
|
||||
throw new Error(`Invalid member name for AuthenticatedSafe class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* AuthenticatedSafe ::= SEQUENCE OF ContentInfo
|
||||
* -- Data if unencrypted
|
||||
* -- EncryptedData if password-encrypted
|
||||
* -- EnvelopedData if public key-encrypted
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [contentInfos]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.Repeated({
|
||||
name: (names.contentInfos || ""),
|
||||
value: ContentInfo.schema()
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"contentInfos"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
AuthenticatedSafe.schema({
|
||||
names: {
|
||||
contentInfos: "contentInfos"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for AuthenticatedSafe");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.safeContents = Array.from(asn1.result.contentInfos, element => new ContentInfo({ schema: element }));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: Array.from(this.safeContents, element => element.toSchema())
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
return {
|
||||
safeContents: Array.from(this.safeContents, element => element.toJSON())
|
||||
};
|
||||
}
|
||||
//**********************************************************************************
|
||||
parseInternalValues(parameters)
|
||||
{
|
||||
//region Check input data from "parameters"
|
||||
if((parameters instanceof Object) === false)
|
||||
return Promise.reject("The \"parameters\" must has \"Object\" type");
|
||||
|
||||
if(("safeContents" in parameters) === false)
|
||||
return Promise.reject("Absent mandatory parameter \"safeContents\"");
|
||||
|
||||
if((parameters.safeContents instanceof Array) === false)
|
||||
return Promise.reject("The \"parameters.safeContents\" must has \"Array\" type");
|
||||
|
||||
if(parameters.safeContents.length !== this.safeContents.length)
|
||||
return Promise.reject("Length of \"parameters.safeContents\" must be equal to \"this.safeContents.length\"");
|
||||
//endregion
|
||||
|
||||
//region Initial variables
|
||||
let sequence = Promise.resolve();
|
||||
//endregion
|
||||
|
||||
//region Create value for "this.parsedValue.authenticatedSafe"
|
||||
this.parsedValue = {
|
||||
safeContents: []
|
||||
};
|
||||
|
||||
for(const [index, content] of this.safeContents.entries())
|
||||
{
|
||||
switch(content.contentType)
|
||||
{
|
||||
//region data
|
||||
case "1.2.840.113549.1.7.1":
|
||||
{
|
||||
//region Check that we do have OCTETSTRING as "content"
|
||||
if((content.content instanceof asn1js.OctetString) === false)
|
||||
return Promise.reject("Wrong type of \"this.safeContents[j].content\"");
|
||||
//endregion
|
||||
|
||||
//region Check we have "constructive encoding" for AuthSafe content
|
||||
let authSafeContent = new ArrayBuffer(0);
|
||||
|
||||
if(content.content.valueBlock.isConstructed)
|
||||
{
|
||||
for(const contentValue of content.content.valueBlock.value)
|
||||
authSafeContent = utilConcatBuf(authSafeContent, contentValue.valueBlock.valueHex);
|
||||
}
|
||||
else
|
||||
authSafeContent = content.content.valueBlock.valueHex;
|
||||
//endregion
|
||||
|
||||
//region Parse internal ASN.1 data
|
||||
const asn1 = asn1js.fromBER(authSafeContent);
|
||||
if(asn1.offset === (-1))
|
||||
return Promise.reject("Error during parsing of ASN.1 data inside \"content.content\"");
|
||||
//endregion
|
||||
|
||||
//region Finilly initialize initial values of "SafeContents" type
|
||||
this.parsedValue.safeContents.push({
|
||||
privacyMode: 0, // No privacy, clear data
|
||||
value: new SafeContents({ schema: asn1.result })
|
||||
});
|
||||
//endregion
|
||||
}
|
||||
break;
|
||||
//endregion
|
||||
//region envelopedData
|
||||
case "1.2.840.113549.1.7.3":
|
||||
{
|
||||
//region Initial variables
|
||||
const cmsEnveloped = new EnvelopedData({ schema: content.content });
|
||||
//endregion
|
||||
|
||||
//region Check mandatory parameters
|
||||
if(("recipientCertificate" in parameters.safeContents[index]) === false)
|
||||
return Promise.reject("Absent mandatory parameter \"recipientCertificate\" in \"parameters.safeContents[j]\"");
|
||||
|
||||
const recipientCertificate = parameters.safeContents[index].recipientCertificate;
|
||||
|
||||
if(("recipientKey" in parameters.safeContents[index]) === false)
|
||||
return Promise.reject("Absent mandatory parameter \"recipientKey\" in \"parameters.safeContents[j]\"");
|
||||
|
||||
// noinspection JSUnresolvedVariable
|
||||
const recipientKey = parameters.safeContents[index].recipientKey;
|
||||
//endregion
|
||||
|
||||
//region Decrypt CMS EnvelopedData using first recipient information
|
||||
sequence = sequence.then(
|
||||
() => cmsEnveloped.decrypt(0, {
|
||||
recipientCertificate,
|
||||
recipientPrivateKey: recipientKey
|
||||
})
|
||||
);
|
||||
|
||||
sequence = sequence.then(
|
||||
/**
|
||||
* @param {ArrayBuffer} result
|
||||
*/
|
||||
result =>
|
||||
{
|
||||
const asn1 = asn1js.fromBER(result);
|
||||
if(asn1.offset === (-1))
|
||||
return Promise.reject("Error during parsing of decrypted data");
|
||||
|
||||
this.parsedValue.safeContents.push({
|
||||
privacyMode: 2, // Public-key privacy mode
|
||||
value: new SafeContents({ schema: asn1.result })
|
||||
});
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
);
|
||||
//endregion
|
||||
}
|
||||
break;
|
||||
//endregion
|
||||
//region encryptedData
|
||||
case "1.2.840.113549.1.7.6":
|
||||
{
|
||||
//region Initial variables
|
||||
const cmsEncrypted = new EncryptedData({ schema: content.content });
|
||||
//endregion
|
||||
|
||||
//region Check mandatory parameters
|
||||
if(("password" in parameters.safeContents[index]) === false)
|
||||
return Promise.reject("Absent mandatory parameter \"password\" in \"parameters.safeContents[j]\"");
|
||||
|
||||
const password = parameters.safeContents[index].password;
|
||||
//endregion
|
||||
|
||||
//region Decrypt CMS EncryptedData using password
|
||||
sequence = sequence.then(
|
||||
() => cmsEncrypted.decrypt({
|
||||
password
|
||||
}),
|
||||
error => Promise.reject(error)
|
||||
);
|
||||
//endregion
|
||||
|
||||
//region Initialize internal data
|
||||
sequence = sequence.then(
|
||||
/**
|
||||
* @param {ArrayBuffer} result
|
||||
*/
|
||||
result =>
|
||||
{
|
||||
const asn1 = asn1js.fromBER(result);
|
||||
if(asn1.offset === (-1))
|
||||
return Promise.reject("Error during parsing of decrypted data");
|
||||
|
||||
this.parsedValue.safeContents.push({
|
||||
privacyMode: 1, // Password-based privacy mode
|
||||
value: new SafeContents({ schema: asn1.result })
|
||||
});
|
||||
|
||||
return Promise.resolve();
|
||||
},
|
||||
error => Promise.reject(error)
|
||||
);
|
||||
//endregion
|
||||
}
|
||||
break;
|
||||
//endregion
|
||||
//region default
|
||||
default:
|
||||
throw new Error(`Unknown "contentType" for AuthenticatedSafe: " ${content.contentType}`);
|
||||
//endregion
|
||||
}
|
||||
}
|
||||
//endregion
|
||||
|
||||
return sequence;
|
||||
}
|
||||
//**********************************************************************************
|
||||
makeInternalValues(parameters)
|
||||
{
|
||||
//region Check data in "parsedValue"
|
||||
if(("parsedValue" in this) === false)
|
||||
return Promise.reject("Please run \"parseValues\" first or add \"parsedValue\" manually");
|
||||
|
||||
if((this.parsedValue instanceof Object) === false)
|
||||
return Promise.reject("The \"this.parsedValue\" must has \"Object\" type");
|
||||
|
||||
if((this.parsedValue.safeContents instanceof Array) === false)
|
||||
return Promise.reject("The \"this.parsedValue.safeContents\" must has \"Array\" type");
|
||||
//endregion
|
||||
|
||||
//region Check input data from "parameters"
|
||||
if((parameters instanceof Object) === false)
|
||||
return Promise.reject("The \"parameters\" must has \"Object\" type");
|
||||
|
||||
if(("safeContents" in parameters) === false)
|
||||
return Promise.reject("Absent mandatory parameter \"safeContents\"");
|
||||
|
||||
if((parameters.safeContents instanceof Array) === false)
|
||||
return Promise.reject("The \"parameters.safeContents\" must has \"Array\" type");
|
||||
|
||||
if(parameters.safeContents.length !== this.parsedValue.safeContents.length)
|
||||
return Promise.reject("Length of \"parameters.safeContents\" must be equal to \"this.parsedValue.safeContents\"");
|
||||
//endregion
|
||||
|
||||
//region Initial variables
|
||||
let sequence = Promise.resolve();
|
||||
//endregion
|
||||
|
||||
//region Create internal values from already parsed values
|
||||
this.safeContents = [];
|
||||
|
||||
for(const [index, content] of this.parsedValue.safeContents.entries())
|
||||
{
|
||||
//region Check current "content" value
|
||||
if(("privacyMode" in content) === false)
|
||||
return Promise.reject("The \"privacyMode\" is a mandatory parameter for \"content\"");
|
||||
|
||||
if(("value" in content) === false)
|
||||
return Promise.reject("The \"value\" is a mandatory parameter for \"content\"");
|
||||
|
||||
if((content.value instanceof SafeContents) === false)
|
||||
return Promise.reject("The \"content.value\" must has \"SafeContents\" type");
|
||||
//endregion
|
||||
|
||||
switch(content.privacyMode)
|
||||
{
|
||||
//region No privacy
|
||||
case 0:
|
||||
{
|
||||
const contentBuffer = content.value.toSchema().toBER(false);
|
||||
|
||||
sequence = sequence.then(
|
||||
() =>
|
||||
{
|
||||
this.safeContents.push(new ContentInfo({
|
||||
contentType: "1.2.840.113549.1.7.1",
|
||||
content: new asn1js.OctetString({ valueHex: contentBuffer })
|
||||
}));
|
||||
});
|
||||
}
|
||||
break;
|
||||
//endregion
|
||||
//region Privacy with password
|
||||
case 1:
|
||||
{
|
||||
//region Initial variables
|
||||
const cmsEncrypted = new EncryptedData();
|
||||
|
||||
const currentParameters = parameters.safeContents[index];
|
||||
currentParameters.contentToEncrypt = content.value.toSchema().toBER(false);
|
||||
//endregion
|
||||
|
||||
//region Encrypt CMS EncryptedData using password
|
||||
sequence = sequence.then(
|
||||
() => cmsEncrypted.encrypt(currentParameters),
|
||||
error => Promise.reject(error)
|
||||
);
|
||||
//endregion
|
||||
|
||||
//region Store result content in CMS_CONTENT_INFO type
|
||||
sequence = sequence.then(
|
||||
() =>
|
||||
{
|
||||
this.safeContents.push(new ContentInfo({
|
||||
contentType: "1.2.840.113549.1.7.6",
|
||||
content: cmsEncrypted.toSchema()
|
||||
}));
|
||||
},
|
||||
error => Promise.reject(error)
|
||||
);
|
||||
//endregion
|
||||
}
|
||||
break;
|
||||
//endregion
|
||||
//region Privacy with public key
|
||||
case 2:
|
||||
{
|
||||
//region Initial variables
|
||||
const cmsEnveloped = new EnvelopedData();
|
||||
const contentToEncrypt = content.value.toSchema().toBER(false);
|
||||
//endregion
|
||||
|
||||
//region Check mandatory parameters
|
||||
if(("encryptingCertificate" in parameters.safeContents[index]) === false)
|
||||
return Promise.reject("Absent mandatory parameter \"encryptingCertificate\" in \"parameters.safeContents[i]\"");
|
||||
|
||||
if(("encryptionAlgorithm" in parameters.safeContents[index]) === false)
|
||||
return Promise.reject("Absent mandatory parameter \"encryptionAlgorithm\" in \"parameters.safeContents[i]\"");
|
||||
|
||||
switch(true)
|
||||
{
|
||||
case (parameters.safeContents[index].encryptionAlgorithm.name.toLowerCase() === "aes-cbc"):
|
||||
case (parameters.safeContents[index].encryptionAlgorithm.name.toLowerCase() === "aes-gcm"):
|
||||
break;
|
||||
default:
|
||||
return Promise.reject(`Incorrect parameter "encryptionAlgorithm" in "parameters.safeContents[i]": ${parameters.safeContents[index].encryptionAlgorithm}`);
|
||||
}
|
||||
|
||||
switch(true)
|
||||
{
|
||||
case (parameters.safeContents[index].encryptionAlgorithm.length === 128):
|
||||
case (parameters.safeContents[index].encryptionAlgorithm.length === 192):
|
||||
case (parameters.safeContents[index].encryptionAlgorithm.length === 256):
|
||||
break;
|
||||
default:
|
||||
return Promise.reject(`Incorrect parameter "encryptionAlgorithm.length" in "parameters.safeContents[i]": ${parameters.safeContents[index].encryptionAlgorithm.length}`);
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region Making correct "encryptionAlgorithm" variable
|
||||
const encryptionAlgorithm = parameters.safeContents[index].encryptionAlgorithm;
|
||||
//endregion
|
||||
|
||||
//region Append recipient for enveloped data
|
||||
cmsEnveloped.addRecipientByCertificate(parameters.safeContents[index].encryptingCertificate);
|
||||
//endregion
|
||||
|
||||
//region Making encryption
|
||||
sequence = sequence.then(
|
||||
() => cmsEnveloped.encrypt(encryptionAlgorithm, contentToEncrypt)
|
||||
);
|
||||
|
||||
sequence = sequence.then(
|
||||
() =>
|
||||
{
|
||||
this.safeContents.push(new ContentInfo({
|
||||
contentType: "1.2.840.113549.1.7.3",
|
||||
content: cmsEnveloped.toSchema()
|
||||
}));
|
||||
}
|
||||
);
|
||||
//endregion
|
||||
}
|
||||
break;
|
||||
//endregion
|
||||
//region default
|
||||
default:
|
||||
return Promise.reject(`Incorrect value for "content.privacyMode": ${content.privacyMode}`);
|
||||
//endregion
|
||||
}
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region Return result of the function
|
||||
return sequence.then(
|
||||
() => this,
|
||||
error => Promise.reject(`Error during parsing: ${error}`)
|
||||
);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
244
core/third-party/pkijs/AuthorityKeyIdentifier.js
vendored
Normal file
244
core/third-party/pkijs/AuthorityKeyIdentifier.js
vendored
Normal file
@@ -0,0 +1,244 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import GeneralName from "./GeneralName.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5280
|
||||
*/
|
||||
export default class AuthorityKeyIdentifier
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for AuthorityKeyIdentifier class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
if("keyIdentifier" in parameters)
|
||||
/**
|
||||
* @type {OctetString}
|
||||
* @desc keyIdentifier
|
||||
*/
|
||||
this.keyIdentifier = getParametersValue(parameters, "keyIdentifier", AuthorityKeyIdentifier.defaultValues("keyIdentifier"));
|
||||
|
||||
if("authorityCertIssuer" in parameters)
|
||||
/**
|
||||
* @type {Array.<GeneralName>}
|
||||
* @desc authorityCertIssuer
|
||||
*/
|
||||
this.authorityCertIssuer = getParametersValue(parameters, "authorityCertIssuer", AuthorityKeyIdentifier.defaultValues("authorityCertIssuer"));
|
||||
|
||||
if("authorityCertSerialNumber" in parameters)
|
||||
/**
|
||||
* @type {Integer}
|
||||
* @desc authorityCertIssuer
|
||||
*/
|
||||
this.authorityCertSerialNumber = getParametersValue(parameters, "authorityCertSerialNumber", AuthorityKeyIdentifier.defaultValues("authorityCertSerialNumber"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "keyIdentifier":
|
||||
return new asn1js.OctetString();
|
||||
case "authorityCertIssuer":
|
||||
return [];
|
||||
case "authorityCertSerialNumber":
|
||||
return new asn1js.Integer();
|
||||
default:
|
||||
throw new Error(`Invalid member name for AuthorityKeyIdentifier class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* AuthorityKeyIdentifier OID ::= 2.5.29.35
|
||||
*
|
||||
* AuthorityKeyIdentifier ::= SEQUENCE {
|
||||
* keyIdentifier [0] KeyIdentifier OPTIONAL,
|
||||
* authorityCertIssuer [1] GeneralNames OPTIONAL,
|
||||
* authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL }
|
||||
*
|
||||
* KeyIdentifier ::= OCTET STRING
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [keyIdentifier]
|
||||
* @property {string} [authorityCertIssuer]
|
||||
* @property {string} [authorityCertSerialNumber]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.Primitive({
|
||||
name: (names.keyIdentifier || ""),
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
}
|
||||
}),
|
||||
new asn1js.Constructed({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 1 // [1]
|
||||
},
|
||||
value: [
|
||||
new asn1js.Repeated({
|
||||
name: (names.authorityCertIssuer || ""),
|
||||
value: GeneralName.schema()
|
||||
})
|
||||
]
|
||||
}),
|
||||
new asn1js.Primitive({
|
||||
name: (names.authorityCertSerialNumber || ""),
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 2 // [2]
|
||||
}
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"keyIdentifier",
|
||||
"authorityCertIssuer",
|
||||
"authorityCertSerialNumber"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
AuthorityKeyIdentifier.schema({
|
||||
names: {
|
||||
keyIdentifier: "keyIdentifier",
|
||||
authorityCertIssuer: "authorityCertIssuer",
|
||||
authorityCertSerialNumber: "authorityCertSerialNumber"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for AuthorityKeyIdentifier");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
if("keyIdentifier" in asn1.result)
|
||||
this.keyIdentifier = new asn1js.OctetString({ valueHex: asn1.result.keyIdentifier.valueBlock.valueHex });
|
||||
|
||||
if("authorityCertIssuer" in asn1.result)
|
||||
this.authorityCertIssuer = Array.from(asn1.result.authorityCertIssuer, element => new GeneralName({ schema: element }));
|
||||
|
||||
if("authorityCertSerialNumber" in asn1.result)
|
||||
this.authorityCertSerialNumber = new asn1js.Integer({ valueHex: asn1.result.authorityCertSerialNumber.valueBlock.valueHex });
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Create array for output sequence
|
||||
const outputArray = [];
|
||||
|
||||
if("keyIdentifier" in this)
|
||||
{
|
||||
outputArray.push(new asn1js.Primitive({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
valueHex: this.keyIdentifier.valueBlock.valueHex
|
||||
}));
|
||||
}
|
||||
|
||||
if("authorityCertIssuer" in this)
|
||||
{
|
||||
outputArray.push(new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 1 // [1]
|
||||
},
|
||||
value: Array.from(this.authorityCertIssuer, element => element.toSchema())
|
||||
}));
|
||||
}
|
||||
|
||||
if("authorityCertSerialNumber" in this)
|
||||
{
|
||||
outputArray.push(new asn1js.Primitive({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 2 // [2]
|
||||
},
|
||||
valueHex: this.authorityCertSerialNumber.valueBlock.valueHex
|
||||
}));
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: outputArray
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
const object = {};
|
||||
|
||||
if("keyIdentifier" in this)
|
||||
object.keyIdentifier = this.keyIdentifier.toJSON();
|
||||
|
||||
if("authorityCertIssuer" in this)
|
||||
object.authorityCertIssuer = Array.from(this.authorityCertIssuer, element => element.toJSON());
|
||||
|
||||
if("authorityCertSerialNumber" in this)
|
||||
object.authorityCertSerialNumber = this.authorityCertSerialNumber.toJSON();
|
||||
|
||||
return object;
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
186
core/third-party/pkijs/BasicConstraints.js
vendored
Normal file
186
core/third-party/pkijs/BasicConstraints.js
vendored
Normal file
@@ -0,0 +1,186 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5280
|
||||
*/
|
||||
export default class BasicConstraints
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for BasicConstraints class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
* @property {Object} [cA]
|
||||
* @property {Object} [pathLenConstraint]
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {boolean}
|
||||
* @desc cA
|
||||
*/
|
||||
this.cA = getParametersValue(parameters, "cA", false);
|
||||
|
||||
if("pathLenConstraint" in parameters)
|
||||
/**
|
||||
* @type {number|Integer}
|
||||
* @desc pathLenConstraint
|
||||
*/
|
||||
this.pathLenConstraint = getParametersValue(parameters, "pathLenConstraint", 0);
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "cA":
|
||||
return false;
|
||||
default:
|
||||
throw new Error(`Invalid member name for BasicConstraints class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* BasicConstraints ::= SEQUENCE {
|
||||
* cA BOOLEAN DEFAULT FALSE,
|
||||
* pathLenConstraint INTEGER (0..MAX) OPTIONAL }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [cA]
|
||||
* @property {string} [pathLenConstraint]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.Boolean({
|
||||
optional: true,
|
||||
name: (names.cA || "")
|
||||
}),
|
||||
new asn1js.Integer({
|
||||
optional: true,
|
||||
name: (names.pathLenConstraint || "")
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"cA",
|
||||
"pathLenConstraint"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
BasicConstraints.schema({
|
||||
names: {
|
||||
cA: "cA",
|
||||
pathLenConstraint: "pathLenConstraint"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for BasicConstraints");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
if("cA" in asn1.result)
|
||||
this.cA = asn1.result.cA.valueBlock.value;
|
||||
|
||||
if("pathLenConstraint" in asn1.result)
|
||||
{
|
||||
if(asn1.result.pathLenConstraint.valueBlock.isHexOnly)
|
||||
this.pathLenConstraint = asn1.result.pathLenConstraint;
|
||||
else
|
||||
this.pathLenConstraint = asn1.result.pathLenConstraint.valueBlock.valueDec;
|
||||
}
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Create array for output sequence
|
||||
const outputArray = [];
|
||||
|
||||
if(this.cA !== BasicConstraints.defaultValues("cA"))
|
||||
outputArray.push(new asn1js.Boolean({ value: this.cA }));
|
||||
|
||||
if("pathLenConstraint" in this)
|
||||
{
|
||||
if(this.pathLenConstraint instanceof asn1js.Integer)
|
||||
outputArray.push(this.pathLenConstraint);
|
||||
else
|
||||
outputArray.push(new asn1js.Integer({ value: this.pathLenConstraint }));
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: outputArray
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
const object = {};
|
||||
|
||||
if(this.cA !== BasicConstraints.defaultValues("cA"))
|
||||
object.cA = this.cA;
|
||||
|
||||
if("pathLenConstraint" in this)
|
||||
{
|
||||
if(this.pathLenConstraint instanceof asn1js.Integer)
|
||||
object.pathLenConstraint = this.pathLenConstraint.toJSON();
|
||||
else
|
||||
object.pathLenConstraint = this.pathLenConstraint;
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
562
core/third-party/pkijs/BasicOCSPResponse.js
vendored
Normal file
562
core/third-party/pkijs/BasicOCSPResponse.js
vendored
Normal file
@@ -0,0 +1,562 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, isEqualBuffer, clearProps } from "./pvutils.js";
|
||||
import { getAlgorithmByOID, getCrypto, getEngine } from "./common.js";
|
||||
import ResponseData from "./ResponseData.js";
|
||||
import AlgorithmIdentifier from "./AlgorithmIdentifier.js";
|
||||
import Certificate from "./Certificate.js";
|
||||
import CertID from "./CertID.js";
|
||||
import RelativeDistinguishedNames from "./RelativeDistinguishedNames.js";
|
||||
import CertificateChainValidationEngine from "./CertificateChainValidationEngine.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC6960
|
||||
*/
|
||||
export default class BasicOCSPResponse
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for BasicOCSPResponse class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {ResponseData}
|
||||
* @desc tbsResponseData
|
||||
*/
|
||||
this.tbsResponseData = getParametersValue(parameters, "tbsResponseData", BasicOCSPResponse.defaultValues("tbsResponseData"));
|
||||
/**
|
||||
* @type {AlgorithmIdentifier}
|
||||
* @desc signatureAlgorithm
|
||||
*/
|
||||
this.signatureAlgorithm = getParametersValue(parameters, "signatureAlgorithm", BasicOCSPResponse.defaultValues("signatureAlgorithm"));
|
||||
/**
|
||||
* @type {BitString}
|
||||
* @desc signature
|
||||
*/
|
||||
this.signature = getParametersValue(parameters, "signature", BasicOCSPResponse.defaultValues("signature"));
|
||||
|
||||
if("certs" in parameters)
|
||||
/**
|
||||
* @type {Array.<Certificate>}
|
||||
* @desc certs
|
||||
*/
|
||||
this.certs = getParametersValue(parameters, "certs", BasicOCSPResponse.defaultValues("certs"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "tbsResponseData":
|
||||
return new ResponseData();
|
||||
case "signatureAlgorithm":
|
||||
return new AlgorithmIdentifier();
|
||||
case "signature":
|
||||
return new asn1js.BitString();
|
||||
case "certs":
|
||||
return [];
|
||||
default:
|
||||
throw new Error(`Invalid member name for BasicOCSPResponse class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Compare values with default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
* @param {*} memberValue Value to compare with default value
|
||||
*/
|
||||
static compareWithDefault(memberName, memberValue)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "type":
|
||||
{
|
||||
// noinspection OverlyComplexBooleanExpressionJS
|
||||
let comparisonResult = ((ResponseData.compareWithDefault("tbs", memberValue.tbs)) &&
|
||||
(ResponseData.compareWithDefault("responderID", memberValue.responderID)) &&
|
||||
(ResponseData.compareWithDefault("producedAt", memberValue.producedAt)) &&
|
||||
(ResponseData.compareWithDefault("responses", memberValue.responses)));
|
||||
|
||||
if("responseExtensions" in memberValue)
|
||||
comparisonResult = comparisonResult && (ResponseData.compareWithDefault("responseExtensions", memberValue.responseExtensions));
|
||||
|
||||
return comparisonResult;
|
||||
}
|
||||
case "signatureAlgorithm":
|
||||
return ((memberValue.algorithmId === "") && (("algorithmParams" in memberValue) === false));
|
||||
case "signature":
|
||||
return (memberValue.isEqual(BasicOCSPResponse.defaultValues(memberName)));
|
||||
case "certs":
|
||||
return (memberValue.length === 0);
|
||||
default:
|
||||
throw new Error(`Invalid member name for BasicOCSPResponse class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* BasicOCSPResponse ::= SEQUENCE {
|
||||
* tbsResponseData ResponseData,
|
||||
* signatureAlgorithm AlgorithmIdentifier,
|
||||
* signature BIT STRING,
|
||||
* certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [tbsResponseData]
|
||||
* @property {string} [signatureAlgorithm]
|
||||
* @property {string} [signature]
|
||||
* @property {string} [certs]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || "BasicOCSPResponse"),
|
||||
value: [
|
||||
ResponseData.schema(names.tbsResponseData || {
|
||||
names: {
|
||||
blockName: "BasicOCSPResponse.tbsResponseData"
|
||||
}
|
||||
}),
|
||||
AlgorithmIdentifier.schema(names.signatureAlgorithm || {
|
||||
names: {
|
||||
blockName: "BasicOCSPResponse.signatureAlgorithm"
|
||||
}
|
||||
}),
|
||||
new asn1js.BitString({ name: (names.signature || "BasicOCSPResponse.signature") }),
|
||||
new asn1js.Constructed({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: [
|
||||
new asn1js.Sequence({
|
||||
value: [new asn1js.Repeated({
|
||||
name: "BasicOCSPResponse.certs",
|
||||
value: Certificate.schema(names.certs || {})
|
||||
})]
|
||||
})
|
||||
]
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"BasicOCSPResponse.tbsResponseData",
|
||||
"BasicOCSPResponse.signatureAlgorithm",
|
||||
"BasicOCSPResponse.signature",
|
||||
"BasicOCSPResponse.certs"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
BasicOCSPResponse.schema()
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for BasicOCSPResponse");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.tbsResponseData = new ResponseData({ schema: asn1.result["BasicOCSPResponse.tbsResponseData"] });
|
||||
this.signatureAlgorithm = new AlgorithmIdentifier({ schema: asn1.result["BasicOCSPResponse.signatureAlgorithm"] });
|
||||
this.signature = asn1.result["BasicOCSPResponse.signature"];
|
||||
|
||||
if("BasicOCSPResponse.certs" in asn1.result)
|
||||
this.certs = Array.from(asn1.result["BasicOCSPResponse.certs"], element => new Certificate({ schema: element }));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Create array for output sequence
|
||||
const outputArray = [];
|
||||
|
||||
outputArray.push(this.tbsResponseData.toSchema());
|
||||
outputArray.push(this.signatureAlgorithm.toSchema());
|
||||
outputArray.push(this.signature);
|
||||
|
||||
//region Create array of certificates
|
||||
if("certs" in this)
|
||||
{
|
||||
outputArray.push(new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: [
|
||||
new asn1js.Sequence({
|
||||
value: Array.from(this.certs, element => element.toSchema())
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//endregion
|
||||
//endregion
|
||||
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: outputArray
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
const _object = {
|
||||
tbsResponseData: this.tbsResponseData.toJSON(),
|
||||
signatureAlgorithm: this.signatureAlgorithm.toJSON(),
|
||||
signature: this.signature.toJSON()
|
||||
};
|
||||
|
||||
if("certs" in this)
|
||||
_object.certs = Array.from(this.certs, element => element.toJSON());
|
||||
|
||||
return _object;
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Get OCSP response status for specific certificate
|
||||
* @param {Certificate} certificate Certificate to be checked
|
||||
* @param {Certificate} issuerCertificate Certificate of issuer for certificate to be checked
|
||||
* @returns {Promise}
|
||||
*/
|
||||
getCertificateStatus(certificate, issuerCertificate)
|
||||
{
|
||||
//region Initial variables
|
||||
let sequence = Promise.resolve();
|
||||
|
||||
const result = {
|
||||
isForCertificate: false,
|
||||
status: 2 // 0 = good, 1 = revoked, 2 = unknown
|
||||
};
|
||||
|
||||
const hashesObject = {};
|
||||
|
||||
const certIDs = [];
|
||||
const certIDPromises = [];
|
||||
//endregion
|
||||
|
||||
//region Create all "certIDs" for input certificates
|
||||
for(const response of this.tbsResponseData.responses)
|
||||
{
|
||||
const hashAlgorithm = getAlgorithmByOID(response.certID.hashAlgorithm.algorithmId);
|
||||
if(("name" in hashAlgorithm) === false)
|
||||
return Promise.reject(`Wrong CertID hashing algorithm: ${response.certID.hashAlgorithm.algorithmId}`);
|
||||
|
||||
if((hashAlgorithm.name in hashesObject) === false)
|
||||
{
|
||||
hashesObject[hashAlgorithm.name] = 1;
|
||||
|
||||
const certID = new CertID();
|
||||
|
||||
certIDs.push(certID);
|
||||
certIDPromises.push(certID.createForCertificate(certificate, {
|
||||
hashAlgorithm: hashAlgorithm.name,
|
||||
issuerCertificate
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
sequence = sequence.then(() =>
|
||||
Promise.all(certIDPromises)
|
||||
);
|
||||
//endregion
|
||||
|
||||
//region Compare all response's "certIDs" with identifiers for input certificate
|
||||
sequence = sequence.then(() =>
|
||||
{
|
||||
for(const response of this.tbsResponseData.responses)
|
||||
{
|
||||
for(const id of certIDs)
|
||||
{
|
||||
if(response.certID.isEqual(id))
|
||||
{
|
||||
result.isForCertificate = true;
|
||||
|
||||
try
|
||||
{
|
||||
switch(response.certStatus.idBlock.isConstructed)
|
||||
{
|
||||
case true:
|
||||
if(response.certStatus.idBlock.tagNumber === 1)
|
||||
result.status = 1; // revoked
|
||||
|
||||
break;
|
||||
case false:
|
||||
switch(response.certStatus.idBlock.tagNumber)
|
||||
{
|
||||
case 0: // good
|
||||
result.status = 0;
|
||||
break;
|
||||
case 2: // unknown
|
||||
result.status = 2;
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
catch(ex)
|
||||
{
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
//endregion
|
||||
|
||||
return sequence;
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Make signature for current OCSP Basic Response
|
||||
* @param {Object} privateKey Private key for "subjectPublicKeyInfo" structure
|
||||
* @param {string} [hashAlgorithm="SHA-1"] Hashing algorithm. Default SHA-1
|
||||
* @returns {Promise}
|
||||
*/
|
||||
sign(privateKey, hashAlgorithm = "SHA-1")
|
||||
{
|
||||
//region Initial checking
|
||||
//region Get a private key from function parameter
|
||||
if(typeof privateKey === "undefined")
|
||||
return Promise.reject("Need to provide a private key for signing");
|
||||
//endregion
|
||||
//endregion
|
||||
|
||||
//region Initial variables
|
||||
let sequence = Promise.resolve();
|
||||
let parameters;
|
||||
|
||||
const engine = getEngine();
|
||||
//endregion
|
||||
|
||||
//region Get a "default parameters" for current algorithm and set correct signature algorithm
|
||||
sequence = sequence.then(() => engine.subtle.getSignatureParameters(privateKey, hashAlgorithm));
|
||||
|
||||
sequence = sequence.then(result =>
|
||||
{
|
||||
parameters = result.parameters;
|
||||
this.signatureAlgorithm = result.signatureAlgorithm;
|
||||
});
|
||||
//endregion
|
||||
|
||||
//region Create TBS data for signing
|
||||
sequence = sequence.then(() =>
|
||||
{
|
||||
this.tbsResponseData.tbs = this.tbsResponseData.toSchema(true).toBER(false);
|
||||
});
|
||||
//endregion
|
||||
|
||||
//region Signing TBS data on provided private key
|
||||
sequence = sequence.then(() => engine.subtle.signWithPrivateKey(this.tbsResponseData.tbs, privateKey, parameters));
|
||||
|
||||
sequence = sequence.then(result =>
|
||||
{
|
||||
this.signature = new asn1js.BitString({ valueHex: result });
|
||||
});
|
||||
//endregion
|
||||
|
||||
return sequence;
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Verify existing OCSP Basic Response
|
||||
* @param {Object} parameters Additional parameters
|
||||
* @returns {Promise}
|
||||
*/
|
||||
verify(parameters = {})
|
||||
{
|
||||
//region Initial variables
|
||||
let signerCert = null;
|
||||
|
||||
let certIndex = -1;
|
||||
|
||||
let sequence = Promise.resolve();
|
||||
|
||||
let trustedCerts = [];
|
||||
|
||||
const _this = this;
|
||||
|
||||
const engine = getEngine();
|
||||
//endregion
|
||||
|
||||
//region Check amount of certificates
|
||||
if(("certs" in this) === false)
|
||||
return Promise.reject("No certificates attached to the BasicOCSPResponce");
|
||||
//endregion
|
||||
|
||||
//region Get input values
|
||||
if("trustedCerts" in parameters)
|
||||
trustedCerts = parameters.trustedCerts;
|
||||
//endregion
|
||||
|
||||
//region Aux functions
|
||||
/**
|
||||
* Check CA flag for the certificate
|
||||
* @param {Certificate} cert Certificate to find CA flag for
|
||||
* @returns {*}
|
||||
*/
|
||||
function checkCA(cert)
|
||||
{
|
||||
//region Do not include signer's certificate
|
||||
if((cert.issuer.isEqual(signerCert.issuer) === true) && (cert.serialNumber.isEqual(signerCert.serialNumber) === true))
|
||||
return null;
|
||||
//endregion
|
||||
|
||||
let isCA = false;
|
||||
|
||||
for(const extension of cert.extensions)
|
||||
{
|
||||
if(extension.extnID === "2.5.29.19") // BasicConstraints
|
||||
{
|
||||
if("cA" in extension.parsedValue)
|
||||
{
|
||||
if(extension.parsedValue.cA === true)
|
||||
isCA = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(isCA)
|
||||
return cert;
|
||||
|
||||
return null;
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region Get a "crypto" extension
|
||||
const crypto = getCrypto();
|
||||
if(typeof crypto === "undefined")
|
||||
return Promise.reject("Unable to create WebCrypto object");
|
||||
//endregion
|
||||
|
||||
//region Find correct value for "responderID"
|
||||
switch(true)
|
||||
{
|
||||
case (this.tbsResponseData.responderID instanceof RelativeDistinguishedNames): // [1] Name
|
||||
sequence = sequence.then(() =>
|
||||
{
|
||||
for(const [index, certificate] of _this.certs.entries())
|
||||
{
|
||||
if(certificate.subject.isEqual(_this.tbsResponseData.responderID))
|
||||
{
|
||||
certIndex = index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
break;
|
||||
case (this.tbsResponseData.responderID instanceof asn1js.OctetString): // [2] KeyHash
|
||||
sequence = sequence.then(() => Promise.all(Array.from(_this.certs, element =>
|
||||
crypto.digest({ name: "sha-1" }, new Uint8Array(element.subjectPublicKeyInfo.subjectPublicKey.valueBlock.valueHex)))).then(results =>
|
||||
{
|
||||
for(const [index, ] of _this.certs.entries())
|
||||
{
|
||||
if(isEqualBuffer(results[index], _this.tbsResponseData.responderID.valueBlock.valueHex))
|
||||
{
|
||||
certIndex = index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}));
|
||||
break;
|
||||
default:
|
||||
return Promise.reject("Wrong value for responderID");
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region Make additional verification for signer's certificate
|
||||
sequence = sequence.then(() =>
|
||||
{
|
||||
if(certIndex === (-1))
|
||||
return Promise.reject("Correct certificate was not found in OCSP response");
|
||||
|
||||
signerCert = this.certs[certIndex];
|
||||
|
||||
return Promise.all(Array.from(_this.certs, element => checkCA(element))).then(promiseResults =>
|
||||
{
|
||||
const additionalCerts = [];
|
||||
additionalCerts.push(signerCert);
|
||||
|
||||
for(const promiseResult of promiseResults)
|
||||
{
|
||||
if(promiseResult !== null)
|
||||
additionalCerts.push(promiseResult);
|
||||
}
|
||||
|
||||
const certChain = new CertificateChainValidationEngine({
|
||||
certs: additionalCerts,
|
||||
trustedCerts
|
||||
});
|
||||
|
||||
return certChain.verify().then(verificationResult =>
|
||||
{
|
||||
if(verificationResult.result === true)
|
||||
return Promise.resolve();
|
||||
|
||||
return Promise.reject("Validation of signer's certificate failed");
|
||||
}, error =>
|
||||
Promise.reject(`Validation of signer's certificate failed with error: ${((error instanceof Object) ? error.resultMessage : error)}`)
|
||||
);
|
||||
}, promiseError =>
|
||||
Promise.reject(`Error during checking certificates for CA flag: ${promiseError}`)
|
||||
);
|
||||
});
|
||||
//endregion
|
||||
|
||||
sequence = sequence.then(() => engine.subtle.verifyWithPublicKey(this.tbsResponseData.tbs, this.signature, this.certs[certIndex].subjectPublicKeyInfo, this.signatureAlgorithm));
|
||||
|
||||
return sequence;
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
181
core/third-party/pkijs/CAVersion.js
vendored
Normal file
181
core/third-party/pkijs/CAVersion.js
vendored
Normal file
@@ -0,0 +1,181 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, utilConcatBuf } from "./pvutils.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from https://docs.microsoft.com/en-us/windows/desktop/seccrypto/certification-authority-renewal
|
||||
*/
|
||||
export default class CAVersion
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for CAVersion class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {number}
|
||||
* @desc certificateIndex
|
||||
*/
|
||||
this.certificateIndex = getParametersValue(parameters, "certificateIndex", CAVersion.defaultValues("certificateIndex"));
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @desc keyIndex
|
||||
*/
|
||||
this.keyIndex = getParametersValue(parameters, "keyIndex", CAVersion.defaultValues("keyIndex"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "certificateIndex":
|
||||
case "keyIndex":
|
||||
return 0;
|
||||
default:
|
||||
throw new Error(`Invalid member name for CAVersion class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* CAVersion ::= INTEGER
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
return (new asn1js.Integer());
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Check the schema is valid
|
||||
if(schema.constructor.blockName() !== asn1js.Integer.blockName())
|
||||
throw new Error("Object's schema was not verified against input data for CAVersion");
|
||||
//endregion
|
||||
|
||||
//region Check length of the input value and correct it if needed
|
||||
let value = schema.valueBlock.valueHex.slice(0);
|
||||
const valueView = new Uint8Array(value);
|
||||
|
||||
switch(true)
|
||||
{
|
||||
case (value.byteLength < 4):
|
||||
{
|
||||
const tempValue = new ArrayBuffer(4);
|
||||
const tempValueView = new Uint8Array(tempValue);
|
||||
|
||||
tempValueView.set(valueView, 4 - value.byteLength);
|
||||
|
||||
value = tempValue.slice(0);
|
||||
}
|
||||
break;
|
||||
case (value.byteLength > 4):
|
||||
{
|
||||
const tempValue = new ArrayBuffer(4);
|
||||
const tempValueView = new Uint8Array(tempValue);
|
||||
|
||||
tempValueView.set(valueView.slice(0, 4));
|
||||
|
||||
value = tempValue.slice(0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
const keyIndexBuffer = value.slice(0, 2);
|
||||
const keyIndexView8 = new Uint8Array(keyIndexBuffer);
|
||||
let temp = keyIndexView8[0];
|
||||
keyIndexView8[0] = keyIndexView8[1];
|
||||
keyIndexView8[1] = temp;
|
||||
|
||||
const keyIndexView16 = new Uint16Array(keyIndexBuffer);
|
||||
|
||||
this.keyIndex = keyIndexView16[0];
|
||||
|
||||
const certificateIndexBuffer = value.slice(2);
|
||||
const certificateIndexView8 = new Uint8Array(certificateIndexBuffer);
|
||||
temp = certificateIndexView8[0];
|
||||
certificateIndexView8[0] = certificateIndexView8[1];
|
||||
certificateIndexView8[1] = temp;
|
||||
|
||||
const certificateIndexView16 = new Uint16Array(certificateIndexBuffer);
|
||||
|
||||
this.certificateIndex = certificateIndexView16[0];
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Create raw values
|
||||
const certificateIndexBuffer = new ArrayBuffer(2);
|
||||
const certificateIndexView = new Uint16Array(certificateIndexBuffer);
|
||||
|
||||
certificateIndexView[0] = this.certificateIndex;
|
||||
|
||||
const certificateIndexView8 = new Uint8Array(certificateIndexBuffer);
|
||||
let temp = certificateIndexView8[0];
|
||||
certificateIndexView8[0] = certificateIndexView8[1];
|
||||
certificateIndexView8[1] = temp;
|
||||
|
||||
const keyIndexBuffer = new ArrayBuffer(2);
|
||||
const keyIndexView = new Uint16Array(keyIndexBuffer);
|
||||
|
||||
keyIndexView[0] = this.keyIndex;
|
||||
|
||||
const keyIndexView8 = new Uint8Array(keyIndexBuffer);
|
||||
temp = keyIndexView8[0];
|
||||
keyIndexView8[0] = keyIndexView8[1];
|
||||
keyIndexView8[1] = temp;
|
||||
//endregion
|
||||
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Integer({
|
||||
valueHex: utilConcatBuf(keyIndexBuffer, certificateIndexBuffer)
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
return {
|
||||
certificateIndex: this.certificateIndex,
|
||||
keyIndex: this.keyIndex
|
||||
};
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
209
core/third-party/pkijs/CRLBag.js
vendored
Normal file
209
core/third-party/pkijs/CRLBag.js
vendored
Normal file
@@ -0,0 +1,209 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import CertificateRevocationList from "./CertificateRevocationList.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC7292
|
||||
*/
|
||||
export default class CRLBag
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for CRLBag class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {string}
|
||||
* @desc crlId
|
||||
*/
|
||||
this.crlId = getParametersValue(parameters, "crlId", CRLBag.defaultValues("crlId"));
|
||||
/**
|
||||
* @type {*}
|
||||
* @desc crlValue
|
||||
*/
|
||||
this.crlValue = getParametersValue(parameters, "crlValue", CRLBag.defaultValues("crlValue"));
|
||||
|
||||
if("parsedValue" in parameters)
|
||||
/**
|
||||
* @type {*}
|
||||
* @desc parsedValue
|
||||
*/
|
||||
this.parsedValue = getParametersValue(parameters, "parsedValue", CRLBag.defaultValues("parsedValue"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "crlId":
|
||||
return "";
|
||||
case "crlValue":
|
||||
return (new asn1js.Any());
|
||||
case "parsedValue":
|
||||
return {};
|
||||
default:
|
||||
throw new Error(`Invalid member name for CRLBag class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Compare values with default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
* @param {*} memberValue Value to compare with default value
|
||||
*/
|
||||
static compareWithDefault(memberName, memberValue)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "crlId":
|
||||
return (memberValue === "");
|
||||
case "crlValue":
|
||||
return (memberValue instanceof asn1js.Any);
|
||||
case "parsedValue":
|
||||
return ((memberValue instanceof Object) && (Object.keys(memberValue).length === 0));
|
||||
default:
|
||||
throw new Error(`Invalid member name for CRLBag class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* CRLBag ::= SEQUENCE {
|
||||
* crlId BAG-TYPE.&id ({CRLTypes}),
|
||||
* crlValue [0] EXPLICIT BAG-TYPE.&Type ({CRLTypes}{@crlId})
|
||||
*}
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [id]
|
||||
* @property {string} [value]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.ObjectIdentifier({ name: (names.id || "id") }),
|
||||
new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: [new asn1js.Any({ name: (names.value || "value") })] // EXPLICIT ANY value
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"crlId",
|
||||
"crlValue"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
CRLBag.schema({
|
||||
names: {
|
||||
id: "crlId",
|
||||
value: "crlValue"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for CRLBag");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.crlId = asn1.result.crlId.valueBlock.toString();
|
||||
this.crlValue = asn1.result.crlValue;
|
||||
|
||||
switch(this.crlId)
|
||||
{
|
||||
case "1.2.840.113549.1.9.23.1": // x509CRL
|
||||
{
|
||||
const asn1Inner = asn1js.fromBER(this.certValue.valueBlock.valueHex);
|
||||
this.parsedValue = new CertificateRevocationList({ schema: asn1Inner.result });
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Incorrect "crlId" value in CRLBag: ${this.crlId}`);
|
||||
}
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
if("parsedValue" in this)
|
||||
{
|
||||
this.certId = "1.2.840.113549.1.9.23.1";
|
||||
this.certValue = new asn1js.OctetString({ valueHex: this.parsedValue.toSchema().toBER(false) });
|
||||
}
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
value: [
|
||||
new asn1js.ObjectIdentifier({ value: this.crlId }),
|
||||
new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: [this.crlValue.toSchema()]
|
||||
})
|
||||
]
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
return {
|
||||
crlId: this.crlId,
|
||||
crlValue: this.crlValue.toJSON()
|
||||
};
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
134
core/third-party/pkijs/CRLDistributionPoints.js
vendored
Normal file
134
core/third-party/pkijs/CRLDistributionPoints.js
vendored
Normal file
@@ -0,0 +1,134 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import DistributionPoint from "./DistributionPoint.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5280
|
||||
*/
|
||||
export default class CRLDistributionPoints
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for CRLDistributionPoints class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {Array.<DistributionPoint>}
|
||||
* @desc distributionPoints
|
||||
*/
|
||||
this.distributionPoints = getParametersValue(parameters, "distributionPoints", CRLDistributionPoints.defaultValues("distributionPoints"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "distributionPoints":
|
||||
return [];
|
||||
default:
|
||||
throw new Error(`Invalid member name for CRLDistributionPoints class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [distributionPoints]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.Repeated({
|
||||
name: (names.distributionPoints || ""),
|
||||
value: DistributionPoint.schema()
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"distributionPoints"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
CRLDistributionPoints.schema({
|
||||
names: {
|
||||
distributionPoints: "distributionPoints"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for CRLDistributionPoints");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.distributionPoints = Array.from(asn1.result.distributionPoints, element => new DistributionPoint({ schema: element }));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: Array.from(this.distributionPoints, element => element.toSchema())
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
return {
|
||||
distributionPoints: Array.from(this.distributionPoints, element => element.toJSON())
|
||||
};
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
229
core/third-party/pkijs/CertBag.js
vendored
Normal file
229
core/third-party/pkijs/CertBag.js
vendored
Normal file
@@ -0,0 +1,229 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import Certificate from "./Certificate.js";
|
||||
import AttributeCertificateV2 from "./AttributeCertificateV2.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC7292
|
||||
*/
|
||||
export default class CertBag
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for CertBag class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {string}
|
||||
* @desc certId
|
||||
*/
|
||||
this.certId = getParametersValue(parameters, "certId", CertBag.defaultValues("certId"));
|
||||
/**
|
||||
* @type {*}
|
||||
* @desc certValue
|
||||
*/
|
||||
this.certValue = getParametersValue(parameters, "certValue", CertBag.defaultValues("certValue"));
|
||||
|
||||
if("parsedValue" in parameters)
|
||||
/**
|
||||
* @type {*}
|
||||
* @desc parsedValue
|
||||
*/
|
||||
this.parsedValue = getParametersValue(parameters, "parsedValue", CertBag.defaultValues("parsedValue"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "certId":
|
||||
return "";
|
||||
case "certValue":
|
||||
return (new asn1js.Any());
|
||||
case "parsedValue":
|
||||
return {};
|
||||
default:
|
||||
throw new Error(`Invalid member name for CertBag class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Compare values with default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
* @param {*} memberValue Value to compare with default value
|
||||
*/
|
||||
static compareWithDefault(memberName, memberValue)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "certId":
|
||||
return (memberValue === "");
|
||||
case "certValue":
|
||||
return (memberValue instanceof asn1js.Any);
|
||||
case "parsedValue":
|
||||
return ((memberValue instanceof Object) && (Object.keys(memberValue).length === 0));
|
||||
default:
|
||||
throw new Error(`Invalid member name for CertBag class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* CertBag ::= SEQUENCE {
|
||||
* certId BAG-TYPE.&id ({CertTypes}),
|
||||
* certValue [0] EXPLICIT BAG-TYPE.&Type ({CertTypes}{@certId})
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [id]
|
||||
* @property {string} [value]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.ObjectIdentifier({ name: (names.id || "id") }),
|
||||
new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: [new asn1js.Any({ name: (names.value || "value") })] // EXPLICIT ANY value
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"certId",
|
||||
"certValue"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
CertBag.schema({
|
||||
names: {
|
||||
id: "certId",
|
||||
value: "certValue"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for CertBag");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.certId = asn1.result.certId.valueBlock.toString();
|
||||
this.certValue = asn1.result.certValue;
|
||||
|
||||
switch(this.certId)
|
||||
{
|
||||
case "1.2.840.113549.1.9.22.1": // x509Certificate
|
||||
{
|
||||
const asn1Inner = asn1js.fromBER(this.certValue.valueBlock.valueHex);
|
||||
|
||||
try
|
||||
{
|
||||
this.parsedValue = new Certificate({ schema: asn1Inner.result });
|
||||
}
|
||||
catch(ex) // In some realizations the same OID used for attribute certificates
|
||||
{
|
||||
this.parsedValue = new AttributeCertificateV2({ schema: asn1Inner.result });
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "1.2.840.113549.1.9.22.3": // attributeCertificate - (!!!) THIS OID IS SUBJECT FOR CHANGE IN FUTURE (!!!)
|
||||
{
|
||||
const asn1Inner = asn1js.fromBER(this.certValue.valueBlock.valueHex);
|
||||
this.parsedValue = new AttributeCertificateV2({ schema: asn1Inner.result });
|
||||
}
|
||||
break;
|
||||
case "1.2.840.113549.1.9.22.2": // sdsiCertificate
|
||||
default:
|
||||
throw new Error(`Incorrect "certId" value in CertBag: ${this.certId}`);
|
||||
}
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
if("parsedValue" in this)
|
||||
{
|
||||
if("acinfo" in this.parsedValue) // attributeCertificate
|
||||
this.certId = "1.2.840.113549.1.9.22.3";
|
||||
else // x509Certificate
|
||||
this.certId = "1.2.840.113549.1.9.22.1";
|
||||
|
||||
this.certValue = new asn1js.OctetString({ valueHex: this.parsedValue.toSchema().toBER(false) });
|
||||
}
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
value: [
|
||||
new asn1js.ObjectIdentifier({ value: this.certId }),
|
||||
new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: [(("toSchema" in this.certValue) ? this.certValue.toSchema() : this.certValue)]
|
||||
})
|
||||
]
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
return {
|
||||
certId: this.certId,
|
||||
certValue: this.certValue.toJSON()
|
||||
};
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
306
core/third-party/pkijs/CertID.js
vendored
Normal file
306
core/third-party/pkijs/CertID.js
vendored
Normal file
@@ -0,0 +1,306 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, isEqualBuffer, clearProps } from "./pvutils.js";
|
||||
import { getCrypto, getOIDByAlgorithm } from "./common.js";
|
||||
import AlgorithmIdentifier from "./AlgorithmIdentifier.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC6960
|
||||
*/
|
||||
export default class CertID
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for CertID class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {AlgorithmIdentifier}
|
||||
* @desc hashAlgorithm
|
||||
*/
|
||||
this.hashAlgorithm = getParametersValue(parameters, "hashAlgorithm", CertID.defaultValues("hashAlgorithm"));
|
||||
/**
|
||||
* @type {OctetString}
|
||||
* @desc issuerNameHash
|
||||
*/
|
||||
this.issuerNameHash = getParametersValue(parameters, "issuerNameHash", CertID.defaultValues("issuerNameHash"));
|
||||
/**
|
||||
* @type {OctetString}
|
||||
* @desc issuerKeyHash
|
||||
*/
|
||||
this.issuerKeyHash = getParametersValue(parameters, "issuerKeyHash", CertID.defaultValues("issuerKeyHash"));
|
||||
/**
|
||||
* @type {Integer}
|
||||
* @desc serialNumber
|
||||
*/
|
||||
this.serialNumber = getParametersValue(parameters, "serialNumber", CertID.defaultValues("serialNumber"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "hashAlgorithm":
|
||||
return new AlgorithmIdentifier();
|
||||
case "issuerNameHash":
|
||||
case "issuerKeyHash":
|
||||
return new asn1js.OctetString();
|
||||
case "serialNumber":
|
||||
return new asn1js.Integer();
|
||||
default:
|
||||
throw new Error(`Invalid member name for CertID class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Compare values with default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
* @param {*} memberValue Value to compare with default value
|
||||
*/
|
||||
static compareWithDefault(memberName, memberValue)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "hashAlgorithm":
|
||||
return ((memberValue.algorithmId === "") && (("algorithmParams" in memberValue) === false));
|
||||
case "issuerNameHash":
|
||||
case "issuerKeyHash":
|
||||
case "serialNumber":
|
||||
return (memberValue.isEqual(CertID.defaultValues(memberName)));
|
||||
default:
|
||||
throw new Error(`Invalid member name for CertID class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* CertID ::= SEQUENCE {
|
||||
* hashAlgorithm AlgorithmIdentifier,
|
||||
* issuerNameHash OCTET STRING, -- Hash of issuer's DN
|
||||
* issuerKeyHash OCTET STRING, -- Hash of issuer's public key
|
||||
* serialNumber CertificateSerialNumber }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [hashAlgorithm]
|
||||
* @property {string} [hashAlgorithmObject]
|
||||
* @property {string} [issuerNameHash]
|
||||
* @property {string} [issuerKeyHash]
|
||||
* @property {string} [serialNumber]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
AlgorithmIdentifier.schema(names.hashAlgorithmObject || {
|
||||
names: {
|
||||
blockName: (names.hashAlgorithm || "")
|
||||
}
|
||||
}),
|
||||
new asn1js.OctetString({ name: (names.issuerNameHash || "") }),
|
||||
new asn1js.OctetString({ name: (names.issuerKeyHash || "") }),
|
||||
new asn1js.Integer({ name: (names.serialNumber || "") })
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"hashAlgorithm",
|
||||
"issuerNameHash",
|
||||
"issuerKeyHash",
|
||||
"serialNumber"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
CertID.schema({
|
||||
names: {
|
||||
hashAlgorithm: "hashAlgorithm",
|
||||
issuerNameHash: "issuerNameHash",
|
||||
issuerKeyHash: "issuerKeyHash",
|
||||
serialNumber: "serialNumber"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for CertID");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.hashAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.hashAlgorithm });
|
||||
this.issuerNameHash = asn1.result.issuerNameHash;
|
||||
this.issuerKeyHash = asn1.result.issuerKeyHash;
|
||||
this.serialNumber = asn1.result.serialNumber;
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: [
|
||||
this.hashAlgorithm.toSchema(),
|
||||
this.issuerNameHash,
|
||||
this.issuerKeyHash,
|
||||
this.serialNumber
|
||||
]
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
return {
|
||||
hashAlgorithm: this.hashAlgorithm.toJSON(),
|
||||
issuerNameHash: this.issuerNameHash.toJSON(),
|
||||
issuerKeyHash: this.issuerKeyHash.toJSON(),
|
||||
serialNumber: this.serialNumber.toJSON()
|
||||
};
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Check that two "CertIDs" are equal
|
||||
* @param {CertID} certificateID Identifier of the certificate to be checked
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isEqual(certificateID)
|
||||
{
|
||||
//region Check "hashAlgorithm"
|
||||
if(!this.hashAlgorithm.algorithmId === certificateID.hashAlgorithm.algorithmId)
|
||||
return false;
|
||||
//endregion
|
||||
|
||||
//region Check "issuerNameHash"
|
||||
if(isEqualBuffer(this.issuerNameHash.valueBlock.valueHex, certificateID.issuerNameHash.valueBlock.valueHex) === false)
|
||||
return false;
|
||||
//endregion
|
||||
|
||||
//region Check "issuerKeyHash"
|
||||
if(isEqualBuffer(this.issuerKeyHash.valueBlock.valueHex, certificateID.issuerKeyHash.valueBlock.valueHex) === false)
|
||||
return false;
|
||||
//endregion
|
||||
|
||||
//region Check "serialNumber"
|
||||
if(!this.serialNumber.isEqual(certificateID.serialNumber))
|
||||
return false;
|
||||
//endregion
|
||||
|
||||
return true;
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Making OCSP certificate identifier for specific certificate
|
||||
* @param {Certificate} certificate Certificate making OCSP Request for
|
||||
* @param {Object} parameters Additional parameters
|
||||
* @returns {Promise}
|
||||
*/
|
||||
createForCertificate(certificate, parameters)
|
||||
{
|
||||
//region Initial variables
|
||||
let sequence = Promise.resolve();
|
||||
|
||||
let issuerCertificate;
|
||||
//endregion
|
||||
|
||||
//region Get a "crypto" extension
|
||||
const crypto = getCrypto();
|
||||
if(typeof crypto === "undefined")
|
||||
return Promise.reject("Unable to create WebCrypto object");
|
||||
//endregion
|
||||
|
||||
//region Check input parameters
|
||||
if(("hashAlgorithm" in parameters) === false)
|
||||
return Promise.reject("Parameter \"hashAlgorithm\" is mandatory for \"OCSP_REQUEST.createForCertificate\"");
|
||||
|
||||
const hashOID = getOIDByAlgorithm({ name: parameters.hashAlgorithm });
|
||||
if(hashOID === "")
|
||||
return Promise.reject(`Incorrect "hashAlgorithm": ${this.hashAlgorithm}`);
|
||||
|
||||
this.hashAlgorithm = new AlgorithmIdentifier({
|
||||
algorithmId: hashOID,
|
||||
algorithmParams: new asn1js.Null()
|
||||
});
|
||||
|
||||
if("issuerCertificate" in parameters)
|
||||
issuerCertificate = parameters.issuerCertificate;
|
||||
else
|
||||
return Promise.reject("Parameter \"issuerCertificate\" is mandatory for \"OCSP_REQUEST.createForCertificate\"");
|
||||
//endregion
|
||||
|
||||
//region Initialize "serialNumber" field
|
||||
this.serialNumber = certificate.serialNumber;
|
||||
//endregion
|
||||
|
||||
//region Create "issuerNameHash"
|
||||
sequence = sequence.then(() =>
|
||||
crypto.digest({ name: parameters.hashAlgorithm }, issuerCertificate.subject.toSchema().toBER(false)),
|
||||
error =>
|
||||
Promise.reject(error)
|
||||
);
|
||||
//endregion
|
||||
|
||||
//region Create "issuerKeyHash"
|
||||
sequence = sequence.then(result =>
|
||||
{
|
||||
this.issuerNameHash = new asn1js.OctetString({ valueHex: result });
|
||||
|
||||
const issuerKeyBuffer = issuerCertificate.subjectPublicKeyInfo.subjectPublicKey.valueBlock.valueHex;
|
||||
|
||||
return crypto.digest({ name: parameters.hashAlgorithm }, issuerKeyBuffer);
|
||||
}, error =>
|
||||
Promise.reject(error)
|
||||
).then(result =>
|
||||
{
|
||||
this.issuerKeyHash = new asn1js.OctetString({ valueHex: result });
|
||||
}, error =>
|
||||
Promise.reject(error)
|
||||
);
|
||||
//endregion
|
||||
|
||||
return sequence;
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
625
core/third-party/pkijs/Certificate.js
vendored
Normal file
625
core/third-party/pkijs/Certificate.js
vendored
Normal file
@@ -0,0 +1,625 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, bufferToHexCodes, clearProps } from "./pvutils.js";
|
||||
import { getCrypto, getEngine } from "./common.js";
|
||||
import AlgorithmIdentifier from "./AlgorithmIdentifier.js";
|
||||
import RelativeDistinguishedNames from "./RelativeDistinguishedNames.js";
|
||||
import Time from "./Time.js";
|
||||
import PublicKeyInfo from "./PublicKeyInfo.js";
|
||||
import Extension from "./Extension.js";
|
||||
import Extensions from "./Extensions.js";
|
||||
//**************************************************************************************
|
||||
function tbsCertificate(parameters = {})
|
||||
{
|
||||
//TBSCertificate ::= SEQUENCE {
|
||||
// version [0] EXPLICIT Version DEFAULT v1,
|
||||
// serialNumber CertificateSerialNumber,
|
||||
// signature AlgorithmIdentifier,
|
||||
// issuer Name,
|
||||
// validity Validity,
|
||||
// subject Name,
|
||||
// subjectPublicKeyInfo SubjectPublicKeyInfo,
|
||||
// issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
|
||||
// -- If present, version MUST be v2 or v3
|
||||
// subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
|
||||
// -- If present, version MUST be v2 or v3
|
||||
// extensions [3] EXPLICIT Extensions OPTIONAL
|
||||
// -- If present, version MUST be v3
|
||||
//}
|
||||
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [tbsCertificateVersion]
|
||||
* @property {string} [tbsCertificateSerialNumber]
|
||||
* @property {string} [signature]
|
||||
* @property {string} [issuer]
|
||||
* @property {string} [tbsCertificateValidity]
|
||||
* @property {string} [notBefore]
|
||||
* @property {string} [notAfter]
|
||||
* @property {string} [subject]
|
||||
* @property {string} [subjectPublicKeyInfo]
|
||||
* @property {string} [tbsCertificateIssuerUniqueID]
|
||||
* @property {string} [tbsCertificateSubjectUniqueID]
|
||||
* @property {string} [extensions]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || "tbsCertificate"),
|
||||
value: [
|
||||
new asn1js.Constructed({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: [
|
||||
new asn1js.Integer({ name: (names.tbsCertificateVersion || "tbsCertificate.version") }) // EXPLICIT integer value
|
||||
]
|
||||
}),
|
||||
new asn1js.Integer({ name: (names.tbsCertificateSerialNumber || "tbsCertificate.serialNumber") }),
|
||||
AlgorithmIdentifier.schema(names.signature || {
|
||||
names: {
|
||||
blockName: "tbsCertificate.signature"
|
||||
}
|
||||
}),
|
||||
RelativeDistinguishedNames.schema(names.issuer || {
|
||||
names: {
|
||||
blockName: "tbsCertificate.issuer"
|
||||
}
|
||||
}),
|
||||
new asn1js.Sequence({
|
||||
name: (names.tbsCertificateValidity || "tbsCertificate.validity"),
|
||||
value: [
|
||||
Time.schema(names.notBefore || {
|
||||
names: {
|
||||
utcTimeName: "tbsCertificate.notBefore",
|
||||
generalTimeName: "tbsCertificate.notBefore"
|
||||
}
|
||||
}),
|
||||
Time.schema(names.notAfter || {
|
||||
names: {
|
||||
utcTimeName: "tbsCertificate.notAfter",
|
||||
generalTimeName: "tbsCertificate.notAfter"
|
||||
}
|
||||
})
|
||||
]
|
||||
}),
|
||||
RelativeDistinguishedNames.schema(names.subject || {
|
||||
names: {
|
||||
blockName: "tbsCertificate.subject"
|
||||
}
|
||||
}),
|
||||
PublicKeyInfo.schema(names.subjectPublicKeyInfo || {
|
||||
names: {
|
||||
blockName: "tbsCertificate.subjectPublicKeyInfo"
|
||||
}
|
||||
}),
|
||||
new asn1js.Primitive({
|
||||
name: (names.tbsCertificateIssuerUniqueID || "tbsCertificate.issuerUniqueID"),
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 1 // [1]
|
||||
}
|
||||
}), // IMPLICIT bistring value
|
||||
new asn1js.Primitive({
|
||||
name: (names.tbsCertificateSubjectUniqueID || "tbsCertificate.subjectUniqueID"),
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 2 // [2]
|
||||
}
|
||||
}), // IMPLICIT bistring value
|
||||
new asn1js.Constructed({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 3 // [3]
|
||||
},
|
||||
value: [Extensions.schema(names.extensions || {
|
||||
names: {
|
||||
blockName: "tbsCertificate.extensions"
|
||||
}
|
||||
})]
|
||||
}) // EXPLICIT SEQUENCE value
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5280
|
||||
*/
|
||||
export default class Certificate
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for Certificate class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {ArrayBuffer}
|
||||
* @desc ToBeSigned (TBS) part of the certificate
|
||||
*/
|
||||
this.tbs = getParametersValue(parameters, "tbs", Certificate.defaultValues("tbs"));
|
||||
/**
|
||||
* @type {number}
|
||||
* @desc Version number
|
||||
*/
|
||||
this.version = getParametersValue(parameters, "version", Certificate.defaultValues("version"));
|
||||
/**
|
||||
* @type {Integer}
|
||||
* @desc Serial number of the certificate
|
||||
*/
|
||||
this.serialNumber = getParametersValue(parameters, "serialNumber", Certificate.defaultValues("serialNumber"));
|
||||
/**
|
||||
* @type {AlgorithmIdentifier}
|
||||
* @desc This field contains the algorithm identifier for the algorithm used by the CA to sign the certificate
|
||||
*/
|
||||
this.signature = getParametersValue(parameters, "signature", Certificate.defaultValues("signature"));
|
||||
/**
|
||||
* @type {RelativeDistinguishedNames}
|
||||
* @desc The issuer field identifies the entity that has signed and issued the certificate
|
||||
*/
|
||||
this.issuer = getParametersValue(parameters, "issuer", Certificate.defaultValues("issuer"));
|
||||
/**
|
||||
* @type {Time}
|
||||
* @desc The date on which the certificate validity period begins
|
||||
*/
|
||||
this.notBefore = getParametersValue(parameters, "notBefore", Certificate.defaultValues("notBefore"));
|
||||
/**
|
||||
* @type {Time}
|
||||
* @desc The date on which the certificate validity period ends
|
||||
*/
|
||||
this.notAfter = getParametersValue(parameters, "notAfter", Certificate.defaultValues("notAfter"));
|
||||
/**
|
||||
* @type {RelativeDistinguishedNames}
|
||||
* @desc The subject field identifies the entity associated with the public key stored in the subject public key field
|
||||
*/
|
||||
this.subject = getParametersValue(parameters, "subject", Certificate.defaultValues("subject"));
|
||||
/**
|
||||
* @type {PublicKeyInfo}
|
||||
* @desc This field is used to carry the public key and identify the algorithm with which the key is used
|
||||
*/
|
||||
this.subjectPublicKeyInfo = getParametersValue(parameters, "subjectPublicKeyInfo", Certificate.defaultValues("subjectPublicKeyInfo"));
|
||||
|
||||
if("issuerUniqueID" in parameters)
|
||||
/**
|
||||
* @type {ArrayBuffer}
|
||||
* @desc The subject and issuer unique identifiers are present in the certificate to handle the possibility of reuse of subject and/or issuer names over time
|
||||
*/
|
||||
this.issuerUniqueID = getParametersValue(parameters, "issuerUniqueID", Certificate.defaultValues("issuerUniqueID"));
|
||||
|
||||
if("subjectUniqueID" in parameters)
|
||||
/**
|
||||
* @type {ArrayBuffer}
|
||||
* @desc The subject and issuer unique identifiers are present in the certificate to handle the possibility of reuse of subject and/or issuer names over time
|
||||
*/
|
||||
this.subjectUniqueID = getParametersValue(parameters, "subjectUniqueID", Certificate.defaultValues("subjectUniqueID"));
|
||||
|
||||
if("extensions" in parameters)
|
||||
/**
|
||||
* @type {Array}
|
||||
* @desc If present, this field is a SEQUENCE of one or more certificate extensions
|
||||
*/
|
||||
this.extensions = getParametersValue(parameters, "extensions", Certificate.defaultValues("extensions"));
|
||||
|
||||
/**
|
||||
* @type {AlgorithmIdentifier}
|
||||
* @desc The signatureAlgorithm field contains the identifier for the cryptographic algorithm used by the CA to sign this certificate
|
||||
*/
|
||||
this.signatureAlgorithm = getParametersValue(parameters, "signatureAlgorithm", Certificate.defaultValues("signatureAlgorithm"));
|
||||
/**
|
||||
* @type {BitString}
|
||||
* @desc The signatureValue field contains a digital signature computed upon the ASN.1 DER encoded tbsCertificate
|
||||
*/
|
||||
this.signatureValue = getParametersValue(parameters, "signatureValue", Certificate.defaultValues("signatureValue"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "tbs":
|
||||
return new ArrayBuffer(0);
|
||||
case "version":
|
||||
return 0;
|
||||
case "serialNumber":
|
||||
return new asn1js.Integer();
|
||||
case "signature":
|
||||
return new AlgorithmIdentifier();
|
||||
case "issuer":
|
||||
return new RelativeDistinguishedNames();
|
||||
case "notBefore":
|
||||
return new Time();
|
||||
case "notAfter":
|
||||
return new Time();
|
||||
case "subject":
|
||||
return new RelativeDistinguishedNames();
|
||||
case "subjectPublicKeyInfo":
|
||||
return new PublicKeyInfo();
|
||||
case "issuerUniqueID":
|
||||
return new ArrayBuffer(0);
|
||||
case "subjectUniqueID":
|
||||
return new ArrayBuffer(0);
|
||||
case "extensions":
|
||||
return [];
|
||||
case "signatureAlgorithm":
|
||||
return new AlgorithmIdentifier();
|
||||
case "signatureValue":
|
||||
return new asn1js.BitString();
|
||||
default:
|
||||
throw new Error(`Invalid member name for Certificate class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* Certificate ::= SEQUENCE {
|
||||
* tbsCertificate TBSCertificate,
|
||||
* signatureAlgorithm AlgorithmIdentifier,
|
||||
* signatureValue BIT STRING }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [tbsCertificate]
|
||||
* @property {string} [signatureAlgorithm]
|
||||
* @property {string} [signatureValue]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
tbsCertificate(names.tbsCertificate),
|
||||
AlgorithmIdentifier.schema(names.signatureAlgorithm || {
|
||||
names: {
|
||||
blockName: "signatureAlgorithm"
|
||||
}
|
||||
}),
|
||||
new asn1js.BitString({ name: (names.signatureValue || "signatureValue") })
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"tbsCertificate",
|
||||
"tbsCertificate.extensions",
|
||||
"tbsCertificate.version",
|
||||
"tbsCertificate.serialNumber",
|
||||
"tbsCertificate.signature",
|
||||
"tbsCertificate.issuer",
|
||||
"tbsCertificate.notBefore",
|
||||
"tbsCertificate.notAfter",
|
||||
"tbsCertificate.subject",
|
||||
"tbsCertificate.subjectPublicKeyInfo",
|
||||
"tbsCertificate.issuerUniqueID",
|
||||
"tbsCertificate.subjectUniqueID",
|
||||
"signatureAlgorithm",
|
||||
"signatureValue"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
Certificate.schema({
|
||||
names: {
|
||||
tbsCertificate: {
|
||||
names: {
|
||||
extensions: {
|
||||
names: {
|
||||
extensions: "tbsCertificate.extensions"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for Certificate");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.tbs = asn1.result.tbsCertificate.valueBeforeDecode;
|
||||
|
||||
if("tbsCertificate.version" in asn1.result)
|
||||
this.version = asn1.result["tbsCertificate.version"].valueBlock.valueDec;
|
||||
this.serialNumber = asn1.result["tbsCertificate.serialNumber"];
|
||||
this.signature = new AlgorithmIdentifier({ schema: asn1.result["tbsCertificate.signature"] });
|
||||
this.issuer = new RelativeDistinguishedNames({ schema: asn1.result["tbsCertificate.issuer"] });
|
||||
this.notBefore = new Time({ schema: asn1.result["tbsCertificate.notBefore"] });
|
||||
this.notAfter = new Time({ schema: asn1.result["tbsCertificate.notAfter"] });
|
||||
this.subject = new RelativeDistinguishedNames({ schema: asn1.result["tbsCertificate.subject"] });
|
||||
this.subjectPublicKeyInfo = new PublicKeyInfo({ schema: asn1.result["tbsCertificate.subjectPublicKeyInfo"] });
|
||||
if("tbsCertificate.issuerUniqueID" in asn1.result)
|
||||
this.issuerUniqueID = asn1.result["tbsCertificate.issuerUniqueID"].valueBlock.valueHex;
|
||||
if("tbsCertificate.subjectUniqueID" in asn1.result)
|
||||
this.subjectUniqueID = asn1.result["tbsCertificate.subjectUniqueID"].valueBlock.valueHex;
|
||||
if("tbsCertificate.extensions" in asn1.result)
|
||||
this.extensions = Array.from(asn1.result["tbsCertificate.extensions"], element => new Extension({ schema: element }));
|
||||
|
||||
this.signatureAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.signatureAlgorithm });
|
||||
this.signatureValue = asn1.result.signatureValue;
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Create ASN.1 schema for existing values of TBS part for the certificate
|
||||
*/
|
||||
encodeTBS()
|
||||
{
|
||||
//region Create array for output sequence
|
||||
const outputArray = [];
|
||||
|
||||
if(("version" in this) && (this.version !== Certificate.defaultValues("version")))
|
||||
{
|
||||
outputArray.push(new asn1js.Constructed({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: [
|
||||
new asn1js.Integer({ value: this.version }) // EXPLICIT integer value
|
||||
]
|
||||
}));
|
||||
}
|
||||
|
||||
outputArray.push(this.serialNumber);
|
||||
outputArray.push(this.signature.toSchema());
|
||||
outputArray.push(this.issuer.toSchema());
|
||||
|
||||
outputArray.push(new asn1js.Sequence({
|
||||
value: [
|
||||
this.notBefore.toSchema(),
|
||||
this.notAfter.toSchema()
|
||||
]
|
||||
}));
|
||||
|
||||
outputArray.push(this.subject.toSchema());
|
||||
outputArray.push(this.subjectPublicKeyInfo.toSchema());
|
||||
|
||||
if("issuerUniqueID" in this)
|
||||
{
|
||||
outputArray.push(new asn1js.Primitive({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 1 // [1]
|
||||
},
|
||||
valueHex: this.issuerUniqueID
|
||||
}));
|
||||
}
|
||||
if("subjectUniqueID" in this)
|
||||
{
|
||||
outputArray.push(new asn1js.Primitive({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 2 // [2]
|
||||
},
|
||||
valueHex: this.subjectUniqueID
|
||||
}));
|
||||
}
|
||||
|
||||
if("extensions" in this)
|
||||
{
|
||||
outputArray.push(new asn1js.Constructed({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 3 // [3]
|
||||
},
|
||||
value: [new asn1js.Sequence({
|
||||
value: Array.from(this.extensions, element => element.toSchema())
|
||||
})]
|
||||
}));
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region Create and return output sequence
|
||||
return (new asn1js.Sequence({
|
||||
value: outputArray
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema(encodeFlag = false)
|
||||
{
|
||||
let tbsSchema = {};
|
||||
|
||||
//region Decode stored TBS value
|
||||
if(encodeFlag === false)
|
||||
{
|
||||
if(this.tbs.length === 0) // No stored certificate TBS part
|
||||
return Certificate.schema().value[0];
|
||||
|
||||
tbsSchema = asn1js.fromBER(this.tbs).result;
|
||||
}
|
||||
//endregion
|
||||
//region Create TBS schema via assembling from TBS parts
|
||||
else
|
||||
tbsSchema = this.encodeTBS();
|
||||
//endregion
|
||||
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: [
|
||||
tbsSchema,
|
||||
this.signatureAlgorithm.toSchema(),
|
||||
this.signatureValue
|
||||
]
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
const object = {
|
||||
tbs: bufferToHexCodes(this.tbs, 0, this.tbs.byteLength),
|
||||
serialNumber: this.serialNumber.toJSON(),
|
||||
signature: this.signature.toJSON(),
|
||||
issuer: this.issuer.toJSON(),
|
||||
notBefore: this.notBefore.toJSON(),
|
||||
notAfter: this.notAfter.toJSON(),
|
||||
subject: this.subject.toJSON(),
|
||||
subjectPublicKeyInfo: this.subjectPublicKeyInfo.toJSON(),
|
||||
signatureAlgorithm: this.signatureAlgorithm.toJSON(),
|
||||
signatureValue: this.signatureValue.toJSON()
|
||||
};
|
||||
|
||||
if(("version" in this) && (this.version !== Certificate.defaultValues("version")))
|
||||
object.version = this.version;
|
||||
|
||||
if("issuerUniqueID" in this)
|
||||
object.issuerUniqueID = bufferToHexCodes(this.issuerUniqueID, 0, this.issuerUniqueID.byteLength);
|
||||
|
||||
if("subjectUniqueID" in this)
|
||||
object.subjectUniqueID = bufferToHexCodes(this.subjectUniqueID, 0, this.subjectUniqueID.byteLength);
|
||||
|
||||
if("extensions" in this)
|
||||
object.extensions = Array.from(this.extensions, element => element.toJSON());
|
||||
|
||||
return object;
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Importing public key for current certificate
|
||||
*/
|
||||
getPublicKey(parameters = null)
|
||||
{
|
||||
return getEngine().subtle.getPublicKey(this.subjectPublicKeyInfo, this.signatureAlgorithm, parameters);
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Get hash value for subject public key (default SHA-1)
|
||||
* @param {String} [hashAlgorithm=SHA-1] Hashing algorithm name
|
||||
*/
|
||||
getKeyHash(hashAlgorithm = "SHA-1")
|
||||
{
|
||||
//region Get a "crypto" extension
|
||||
const crypto = getCrypto();
|
||||
if(typeof crypto === "undefined")
|
||||
return Promise.reject("Unable to create WebCrypto object");
|
||||
//endregion
|
||||
|
||||
return crypto.digest({ name: hashAlgorithm }, new Uint8Array(this.subjectPublicKeyInfo.subjectPublicKey.valueBlock.valueHex));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Make a signature for current value from TBS section
|
||||
* @param {Object} privateKey Private key for "subjectPublicKeyInfo" structure
|
||||
* @param {string} [hashAlgorithm="SHA-1"] Hashing algorithm
|
||||
*/
|
||||
sign(privateKey, hashAlgorithm = "SHA-1")
|
||||
{
|
||||
//region Initial checking
|
||||
//region Check private key
|
||||
if(typeof privateKey === "undefined")
|
||||
return Promise.reject("Need to provide a private key for signing");
|
||||
//endregion
|
||||
//endregion
|
||||
|
||||
//region Initial variables
|
||||
let sequence = Promise.resolve();
|
||||
let parameters;
|
||||
|
||||
const engine = getEngine();
|
||||
//endregion
|
||||
|
||||
//region Get a "default parameters" for current algorithm and set correct signature algorithm
|
||||
sequence = sequence.then(() => engine.subtle.getSignatureParameters(privateKey, hashAlgorithm));
|
||||
|
||||
sequence = sequence.then(result =>
|
||||
{
|
||||
parameters = result.parameters;
|
||||
this.signature = result.signatureAlgorithm;
|
||||
this.signatureAlgorithm = result.signatureAlgorithm;
|
||||
});
|
||||
//endregion
|
||||
|
||||
//region Create TBS data for signing
|
||||
sequence = sequence.then(() =>
|
||||
{
|
||||
this.tbs = this.encodeTBS().toBER(false);
|
||||
});
|
||||
//endregion
|
||||
|
||||
//region Signing TBS data on provided private key
|
||||
sequence = sequence.then(() => engine.subtle.signWithPrivateKey(this.tbs, privateKey, parameters));
|
||||
|
||||
sequence = sequence.then(result =>
|
||||
{
|
||||
this.signatureValue = new asn1js.BitString({ valueHex: result });
|
||||
});
|
||||
//endregion
|
||||
|
||||
return sequence;
|
||||
}
|
||||
//**********************************************************************************
|
||||
verify(issuerCertificate = null)
|
||||
{
|
||||
//region Global variables
|
||||
let subjectPublicKeyInfo = {};
|
||||
//endregion
|
||||
|
||||
//region Set correct "subjectPublicKeyInfo" value
|
||||
if(issuerCertificate !== null)
|
||||
subjectPublicKeyInfo = issuerCertificate.subjectPublicKeyInfo;
|
||||
else
|
||||
{
|
||||
if(this.issuer.isEqual(this.subject)) // Self-signed certificate
|
||||
subjectPublicKeyInfo = this.subjectPublicKeyInfo;
|
||||
}
|
||||
|
||||
if((subjectPublicKeyInfo instanceof PublicKeyInfo) === false)
|
||||
return Promise.reject("Please provide issuer certificate as a parameter");
|
||||
//endregion
|
||||
|
||||
return getEngine().subtle.verifyWithPublicKey(this.tbs, this.signatureValue, subjectPublicKeyInfo, this.signatureAlgorithm);
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
1910
core/third-party/pkijs/CertificateChainValidationEngine.js
vendored
Normal file
1910
core/third-party/pkijs/CertificateChainValidationEngine.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
134
core/third-party/pkijs/CertificatePolicies.js
vendored
Normal file
134
core/third-party/pkijs/CertificatePolicies.js
vendored
Normal file
@@ -0,0 +1,134 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import PolicyInformation from "./PolicyInformation.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5280
|
||||
*/
|
||||
export default class CertificatePolicies
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for CertificatePolicies class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {Array.<PolicyInformation>}
|
||||
* @desc certificatePolicies
|
||||
*/
|
||||
this.certificatePolicies = getParametersValue(parameters, "certificatePolicies", CertificatePolicies.defaultValues("certificatePolicies"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "certificatePolicies":
|
||||
return [];
|
||||
default:
|
||||
throw new Error(`Invalid member name for CertificatePolicies class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [certificatePolicies]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.Repeated({
|
||||
name: (names.certificatePolicies || ""),
|
||||
value: PolicyInformation.schema()
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"certificatePolicies"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
CertificatePolicies.schema({
|
||||
names: {
|
||||
certificatePolicies: "certificatePolicies"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for CertificatePolicies");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.certificatePolicies = Array.from(asn1.result.certificatePolicies, element => new PolicyInformation({ schema: element }));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: Array.from(this.certificatePolicies, element => element.toSchema())
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
return {
|
||||
certificatePolicies: Array.from(this.certificatePolicies, element => element.toJSON())
|
||||
};
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
538
core/third-party/pkijs/CertificateRevocationList.js
vendored
Normal file
538
core/third-party/pkijs/CertificateRevocationList.js
vendored
Normal file
@@ -0,0 +1,538 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, bufferToHexCodes, clearProps } from "./pvutils.js";
|
||||
import { getEngine } from "./common.js";
|
||||
import AlgorithmIdentifier from "./AlgorithmIdentifier.js";
|
||||
import RelativeDistinguishedNames from "./RelativeDistinguishedNames.js";
|
||||
import Time from "./Time.js";
|
||||
import RevokedCertificate from "./RevokedCertificate.js";
|
||||
import Extensions from "./Extensions.js";
|
||||
//**************************************************************************************
|
||||
function tbsCertList(parameters = {})
|
||||
{
|
||||
//TBSCertList ::= SEQUENCE {
|
||||
// version Version OPTIONAL,
|
||||
// -- if present, MUST be v2
|
||||
// signature AlgorithmIdentifier,
|
||||
// issuer Name,
|
||||
// thisUpdate Time,
|
||||
// nextUpdate Time OPTIONAL,
|
||||
// revokedCertificates SEQUENCE OF SEQUENCE {
|
||||
// userCertificate CertificateSerialNumber,
|
||||
// revocationDate Time,
|
||||
// crlEntryExtensions Extensions OPTIONAL
|
||||
// -- if present, version MUST be v2
|
||||
// } OPTIONAL,
|
||||
// crlExtensions [0] EXPLICIT Extensions OPTIONAL
|
||||
// -- if present, version MUST be v2
|
||||
//}
|
||||
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [tbsCertListVersion]
|
||||
* @property {string} [signature]
|
||||
* @property {string} [issuer]
|
||||
* @property {string} [tbsCertListThisUpdate]
|
||||
* @property {string} [tbsCertListNextUpdate]
|
||||
* @property {string} [tbsCertListRevokedCertificates]
|
||||
* @property {string} [crlExtensions]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || "tbsCertList"),
|
||||
value: [
|
||||
new asn1js.Integer({
|
||||
optional: true,
|
||||
name: (names.tbsCertListVersion || "tbsCertList.version"),
|
||||
value: 2
|
||||
}), // EXPLICIT integer value (v2)
|
||||
AlgorithmIdentifier.schema(names.signature || {
|
||||
names: {
|
||||
blockName: "tbsCertList.signature"
|
||||
}
|
||||
}),
|
||||
RelativeDistinguishedNames.schema(names.issuer || {
|
||||
names: {
|
||||
blockName: "tbsCertList.issuer"
|
||||
}
|
||||
}),
|
||||
Time.schema(names.tbsCertListThisUpdate || {
|
||||
names: {
|
||||
utcTimeName: "tbsCertList.thisUpdate",
|
||||
generalTimeName: "tbsCertList.thisUpdate"
|
||||
}
|
||||
}),
|
||||
Time.schema(names.tbsCertListNextUpdate || {
|
||||
names: {
|
||||
utcTimeName: "tbsCertList.nextUpdate",
|
||||
generalTimeName: "tbsCertList.nextUpdate"
|
||||
}
|
||||
}, true),
|
||||
new asn1js.Sequence({
|
||||
optional: true,
|
||||
value: [
|
||||
new asn1js.Repeated({
|
||||
name: (names.tbsCertListRevokedCertificates || "tbsCertList.revokedCertificates"),
|
||||
value: new asn1js.Sequence({
|
||||
value: [
|
||||
new asn1js.Integer(),
|
||||
Time.schema(),
|
||||
Extensions.schema({}, true)
|
||||
]
|
||||
})
|
||||
})
|
||||
]
|
||||
}),
|
||||
new asn1js.Constructed({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: [Extensions.schema(names.crlExtensions || {
|
||||
names: {
|
||||
blockName: "tbsCertList.extensions"
|
||||
}
|
||||
})]
|
||||
}) // EXPLICIT SEQUENCE value
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5280
|
||||
*/
|
||||
export default class CertificateRevocationList {
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for Attribute class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {ArrayBuffer}
|
||||
* @desc tbs
|
||||
*/
|
||||
this.tbs = getParametersValue(parameters, "tbs", CertificateRevocationList.defaultValues("tbs"));
|
||||
/**
|
||||
* @type {number}
|
||||
* @desc version
|
||||
*/
|
||||
this.version = getParametersValue(parameters, "version", CertificateRevocationList.defaultValues("version"));
|
||||
/**
|
||||
* @type {AlgorithmIdentifier}
|
||||
* @desc signature
|
||||
*/
|
||||
this.signature = getParametersValue(parameters, "signature", CertificateRevocationList.defaultValues("signature"));
|
||||
/**
|
||||
* @type {RelativeDistinguishedNames}
|
||||
* @desc issuer
|
||||
*/
|
||||
this.issuer = getParametersValue(parameters, "issuer", CertificateRevocationList.defaultValues("issuer"));
|
||||
/**
|
||||
* @type {Time}
|
||||
* @desc thisUpdate
|
||||
*/
|
||||
this.thisUpdate = getParametersValue(parameters, "thisUpdate", CertificateRevocationList.defaultValues("thisUpdate"));
|
||||
|
||||
if("nextUpdate" in parameters)
|
||||
/**
|
||||
* @type {Time}
|
||||
* @desc nextUpdate
|
||||
*/
|
||||
this.nextUpdate = getParametersValue(parameters, "nextUpdate", CertificateRevocationList.defaultValues("nextUpdate"));
|
||||
|
||||
if("revokedCertificates" in parameters)
|
||||
/**
|
||||
* @type {Array.<RevokedCertificate>}
|
||||
* @desc revokedCertificates
|
||||
*/
|
||||
this.revokedCertificates = getParametersValue(parameters, "revokedCertificates", CertificateRevocationList.defaultValues("revokedCertificates"));
|
||||
|
||||
if("crlExtensions" in parameters)
|
||||
/**
|
||||
* @type {Extensions}
|
||||
* @desc crlExtensions
|
||||
*/
|
||||
this.crlExtensions = getParametersValue(parameters, "crlExtensions", CertificateRevocationList.defaultValues("crlExtensions"));
|
||||
|
||||
/**
|
||||
* @type {AlgorithmIdentifier}
|
||||
* @desc signatureAlgorithm
|
||||
*/
|
||||
this.signatureAlgorithm = getParametersValue(parameters, "signatureAlgorithm", CertificateRevocationList.defaultValues("signatureAlgorithm"));
|
||||
/**
|
||||
* @type {BitString}
|
||||
* @desc signatureValue
|
||||
*/
|
||||
this.signatureValue = getParametersValue(parameters, "signatureValue", CertificateRevocationList.defaultValues("signatureValue"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "tbs":
|
||||
return new ArrayBuffer(0);
|
||||
case "version":
|
||||
return 1;
|
||||
case "signature":
|
||||
return new AlgorithmIdentifier();
|
||||
case "issuer":
|
||||
return new RelativeDistinguishedNames();
|
||||
case "thisUpdate":
|
||||
return new Time();
|
||||
case "nextUpdate":
|
||||
return new Time();
|
||||
case "revokedCertificates":
|
||||
return [];
|
||||
case "crlExtensions":
|
||||
return new Extensions();
|
||||
case "signatureAlgorithm":
|
||||
return new AlgorithmIdentifier();
|
||||
case "signatureValue":
|
||||
return new asn1js.BitString();
|
||||
default:
|
||||
throw new Error(`Invalid member name for CertificateRevocationList class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* CertificateList ::= SEQUENCE {
|
||||
* tbsCertList TBSCertList,
|
||||
* signatureAlgorithm AlgorithmIdentifier,
|
||||
* signatureValue BIT STRING }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [signatureAlgorithm]
|
||||
* @property {string} [signatureValue]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || "CertificateList"),
|
||||
value: [
|
||||
tbsCertList(parameters),
|
||||
AlgorithmIdentifier.schema(names.signatureAlgorithm || {
|
||||
names: {
|
||||
blockName: "signatureAlgorithm"
|
||||
}
|
||||
}),
|
||||
new asn1js.BitString({ name: (names.signatureValue || "signatureValue") })
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"tbsCertList",
|
||||
"tbsCertList.version",
|
||||
"tbsCertList.signature",
|
||||
"tbsCertList.issuer",
|
||||
"tbsCertList.thisUpdate",
|
||||
"tbsCertList.nextUpdate",
|
||||
"tbsCertList.revokedCertificates",
|
||||
"tbsCertList.extensions",
|
||||
"signatureAlgorithm",
|
||||
"signatureValue"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
CertificateRevocationList.schema()
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for CertificateRevocationList");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
// noinspection JSUnresolvedVariable
|
||||
this.tbs = asn1.result.tbsCertList.valueBeforeDecode;
|
||||
|
||||
if("tbsCertList.version" in asn1.result)
|
||||
this.version = asn1.result["tbsCertList.version"].valueBlock.valueDec;
|
||||
this.signature = new AlgorithmIdentifier({ schema: asn1.result["tbsCertList.signature"] });
|
||||
this.issuer = new RelativeDistinguishedNames({ schema: asn1.result["tbsCertList.issuer"] });
|
||||
this.thisUpdate = new Time({ schema: asn1.result["tbsCertList.thisUpdate"] });
|
||||
if("tbsCertList.nextUpdate" in asn1.result)
|
||||
this.nextUpdate = new Time({ schema: asn1.result["tbsCertList.nextUpdate"] });
|
||||
if("tbsCertList.revokedCertificates" in asn1.result)
|
||||
this.revokedCertificates = Array.from(asn1.result["tbsCertList.revokedCertificates"], element => new RevokedCertificate({ schema: element }));
|
||||
if("tbsCertList.extensions" in asn1.result)
|
||||
this.crlExtensions = new Extensions({ schema: asn1.result["tbsCertList.extensions"] });
|
||||
|
||||
this.signatureAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.signatureAlgorithm });
|
||||
this.signatureValue = asn1.result.signatureValue;
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
encodeTBS()
|
||||
{
|
||||
//region Create array for output sequence
|
||||
const outputArray = [];
|
||||
|
||||
if(this.version !== CertificateRevocationList.defaultValues("version"))
|
||||
outputArray.push(new asn1js.Integer({ value: this.version }));
|
||||
|
||||
outputArray.push(this.signature.toSchema());
|
||||
outputArray.push(this.issuer.toSchema());
|
||||
outputArray.push(this.thisUpdate.toSchema());
|
||||
|
||||
if("nextUpdate" in this)
|
||||
outputArray.push(this.nextUpdate.toSchema());
|
||||
|
||||
if("revokedCertificates" in this)
|
||||
{
|
||||
outputArray.push(new asn1js.Sequence({
|
||||
value: Array.from(this.revokedCertificates, element => element.toSchema())
|
||||
}));
|
||||
}
|
||||
|
||||
if("crlExtensions" in this)
|
||||
{
|
||||
outputArray.push(new asn1js.Constructed({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: [
|
||||
this.crlExtensions.toSchema()
|
||||
]
|
||||
}));
|
||||
}
|
||||
//endregion
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
value: outputArray
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema(encodeFlag = false)
|
||||
{
|
||||
//region Decode stored TBS value
|
||||
let tbsSchema;
|
||||
|
||||
if(encodeFlag === false)
|
||||
{
|
||||
if(this.tbs.length === 0) // No stored TBS part
|
||||
return CertificateRevocationList.schema();
|
||||
|
||||
tbsSchema = asn1js.fromBER(this.tbs).result;
|
||||
}
|
||||
//endregion
|
||||
//region Create TBS schema via assembling from TBS parts
|
||||
else
|
||||
tbsSchema = this.encodeTBS();
|
||||
//endregion
|
||||
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: [
|
||||
tbsSchema,
|
||||
this.signatureAlgorithm.toSchema(),
|
||||
this.signatureValue
|
||||
]
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
const object = {
|
||||
tbs: bufferToHexCodes(this.tbs, 0, this.tbs.byteLength),
|
||||
signature: this.signature.toJSON(),
|
||||
issuer: this.issuer.toJSON(),
|
||||
thisUpdate: this.thisUpdate.toJSON(),
|
||||
signatureAlgorithm: this.signatureAlgorithm.toJSON(),
|
||||
signatureValue: this.signatureValue.toJSON()
|
||||
};
|
||||
|
||||
if(this.version !== CertificateRevocationList.defaultValues("version"))
|
||||
object.version = this.version;
|
||||
|
||||
if("nextUpdate" in this)
|
||||
object.nextUpdate = this.nextUpdate.toJSON();
|
||||
|
||||
if("revokedCertificates" in this)
|
||||
object.revokedCertificates = Array.from(this.revokedCertificates, element => element.toJSON());
|
||||
|
||||
if("crlExtensions" in this)
|
||||
object.crlExtensions = this.crlExtensions.toJSON();
|
||||
|
||||
return object;
|
||||
}
|
||||
//**********************************************************************************
|
||||
isCertificateRevoked(certificate)
|
||||
{
|
||||
//region Check that issuer of the input certificate is the same with issuer of this CRL
|
||||
if(this.issuer.isEqual(certificate.issuer) === false)
|
||||
return false;
|
||||
//endregion
|
||||
|
||||
//region Check that there are revoked certificates in this CRL
|
||||
if(("revokedCertificates" in this) === false)
|
||||
return false;
|
||||
//endregion
|
||||
|
||||
//region Search for input certificate in revoked certificates array
|
||||
for(const revokedCertificate of this.revokedCertificates)
|
||||
{
|
||||
if(revokedCertificate.userCertificate.isEqual(certificate.serialNumber))
|
||||
return true;
|
||||
}
|
||||
//endregion
|
||||
|
||||
return false;
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Make a signature for existing CRL data
|
||||
* @param {Object} privateKey Private key for "subjectPublicKeyInfo" structure
|
||||
* @param {string} [hashAlgorithm] Hashing algorithm. Default SHA-1
|
||||
*/
|
||||
sign(privateKey, hashAlgorithm = "SHA-1")
|
||||
{
|
||||
//region Initial checking
|
||||
//region Get a private key from function parameter
|
||||
if(typeof privateKey === "undefined")
|
||||
return Promise.reject("Need to provide a private key for signing");
|
||||
//endregion
|
||||
//endregion
|
||||
|
||||
//region Initial variables
|
||||
let sequence = Promise.resolve();
|
||||
let parameters;
|
||||
|
||||
const engine = getEngine();
|
||||
//endregion
|
||||
|
||||
//region Get a "default parameters" for current algorithm and set correct signature algorithm
|
||||
sequence = sequence.then(() => engine.subtle.getSignatureParameters(privateKey, hashAlgorithm));
|
||||
|
||||
sequence = sequence.then(result =>
|
||||
{
|
||||
parameters = result.parameters;
|
||||
this.signature = result.signatureAlgorithm;
|
||||
this.signatureAlgorithm = result.signatureAlgorithm;
|
||||
});
|
||||
//endregion
|
||||
|
||||
//region Create TBS data for signing
|
||||
sequence = sequence.then(() =>
|
||||
{
|
||||
this.tbs = this.encodeTBS().toBER(false);
|
||||
});
|
||||
//endregion
|
||||
|
||||
//region Signing TBS data on provided private key
|
||||
sequence = sequence.then(() => engine.subtle.signWithPrivateKey(this.tbs, privateKey, parameters));
|
||||
|
||||
sequence = sequence.then(result =>
|
||||
{
|
||||
this.signatureValue = new asn1js.BitString({ valueHex: result });
|
||||
});
|
||||
//endregion
|
||||
|
||||
return sequence;
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Verify existing signature
|
||||
* @param {{[issuerCertificate]: Object, [publicKeyInfo]: Object}} parameters
|
||||
* @returns {*}
|
||||
*/
|
||||
verify(parameters = {})
|
||||
{
|
||||
//region Global variables
|
||||
let sequence = Promise.resolve();
|
||||
|
||||
let subjectPublicKeyInfo = -1;
|
||||
|
||||
const engine = getEngine();
|
||||
//endregion
|
||||
|
||||
//region Get information about CRL issuer certificate
|
||||
if("issuerCertificate" in parameters) // "issuerCertificate" must be of type "Certificate"
|
||||
{
|
||||
subjectPublicKeyInfo = parameters.issuerCertificate.subjectPublicKeyInfo;
|
||||
|
||||
// The CRL issuer name and "issuerCertificate" subject name are not equal
|
||||
if(this.issuer.isEqual(parameters.issuerCertificate.subject) === false)
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
//region In case if there is only public key during verification
|
||||
if("publicKeyInfo" in parameters)
|
||||
subjectPublicKeyInfo = parameters.publicKeyInfo; // Must be of type "PublicKeyInfo"
|
||||
//endregion
|
||||
|
||||
if(("subjectPublicKey" in subjectPublicKeyInfo) === false)
|
||||
return Promise.reject("Issuer's certificate must be provided as an input parameter");
|
||||
//endregion
|
||||
|
||||
//region Check the CRL for unknown critical extensions
|
||||
if("crlExtensions" in this)
|
||||
{
|
||||
for(const extension of this.crlExtensions.extensions)
|
||||
{
|
||||
if(extension.critical)
|
||||
{
|
||||
// We can not be sure that unknown extension has no value for CRL signature
|
||||
if(("parsedValue" in extension) === false)
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
//endregion
|
||||
|
||||
sequence = sequence.then(() => engine.subtle.verifyWithPublicKey(this.tbs, this.signatureValue, subjectPublicKeyInfo, this.signatureAlgorithm));
|
||||
|
||||
return sequence;
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
235
core/third-party/pkijs/CertificateSet.js
vendored
Normal file
235
core/third-party/pkijs/CertificateSet.js
vendored
Normal file
@@ -0,0 +1,235 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import Certificate from "./Certificate.js";
|
||||
import AttributeCertificateV1 from "./AttributeCertificateV1.js";
|
||||
import AttributeCertificateV2 from "./AttributeCertificateV2.js";
|
||||
import OtherCertificateFormat from "./OtherCertificateFormat.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5652
|
||||
*/
|
||||
export default class CertificateSet
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for CertificateSet class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {Array}
|
||||
* @desc certificates
|
||||
*/
|
||||
this.certificates = getParametersValue(parameters, "certificates", CertificateSet.defaultValues("certificates"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "certificates":
|
||||
return [];
|
||||
default:
|
||||
throw new Error(`Invalid member name for Attribute class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* CertificateSet ::= SET OF CertificateChoices
|
||||
*
|
||||
* CertificateChoices ::= CHOICE {
|
||||
* certificate Certificate,
|
||||
* extendedCertificate [0] IMPLICIT ExtendedCertificate, -- Obsolete
|
||||
* v1AttrCert [1] IMPLICIT AttributeCertificateV1, -- Obsolete
|
||||
* v2AttrCert [2] IMPLICIT AttributeCertificateV2,
|
||||
* other [3] IMPLICIT OtherCertificateFormat }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (
|
||||
new asn1js.Set({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.Repeated({
|
||||
name: (names.certificates || "certificates"),
|
||||
value: new asn1js.Choice({
|
||||
value: [
|
||||
Certificate.schema(),
|
||||
new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: [
|
||||
new asn1js.Any()
|
||||
]
|
||||
}), // JUST A STUB
|
||||
new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 1 // [1]
|
||||
},
|
||||
value: AttributeCertificateV1.schema().valueBlock.value
|
||||
}),
|
||||
new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 2 // [2]
|
||||
},
|
||||
value: AttributeCertificateV2.schema().valueBlock.value
|
||||
}),
|
||||
new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 3 // [3]
|
||||
},
|
||||
value: OtherCertificateFormat.schema().valueBlock.value
|
||||
})
|
||||
]
|
||||
})
|
||||
})
|
||||
]
|
||||
})
|
||||
);
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"certificates"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
CertificateSet.schema()
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for CertificateSet");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.certificates = Array.from(asn1.result.certificates || [], element =>
|
||||
{
|
||||
const initialTagNumber = element.idBlock.tagNumber;
|
||||
|
||||
if(element.idBlock.tagClass === 1)
|
||||
return new Certificate({ schema: element });
|
||||
|
||||
//region Making "Sequence" from "Constructed" value
|
||||
const elementSequence = new asn1js.Sequence({
|
||||
value: element.valueBlock.value
|
||||
});
|
||||
//endregion
|
||||
|
||||
switch(initialTagNumber)
|
||||
{
|
||||
case 1:
|
||||
return new AttributeCertificateV1({ schema: elementSequence });
|
||||
case 2:
|
||||
return new AttributeCertificateV2({ schema: elementSequence });
|
||||
case 3:
|
||||
return new OtherCertificateFormat({ schema: elementSequence });
|
||||
case 0:
|
||||
default:
|
||||
}
|
||||
|
||||
return element;
|
||||
});
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Set({
|
||||
value: Array.from(this.certificates, element =>
|
||||
{
|
||||
switch(true)
|
||||
{
|
||||
case (element instanceof Certificate):
|
||||
return element.toSchema();
|
||||
case (element instanceof AttributeCertificateV1):
|
||||
return new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3,
|
||||
tagNumber: 1 // [1]
|
||||
},
|
||||
value: element.toSchema().valueBlock.value
|
||||
});
|
||||
case (element instanceof AttributeCertificateV2):
|
||||
return new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3,
|
||||
tagNumber: 2 // [2]
|
||||
},
|
||||
value: element.toSchema().valueBlock.value
|
||||
});
|
||||
case (element instanceof OtherCertificateFormat):
|
||||
return new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3,
|
||||
tagNumber: 3 // [3]
|
||||
},
|
||||
value: element.toSchema().valueBlock.value
|
||||
});
|
||||
default:
|
||||
}
|
||||
|
||||
return element;
|
||||
})
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
return {
|
||||
certificates: Array.from(this.certificates, element => element.toJSON())
|
||||
};
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
191
core/third-party/pkijs/CertificateTemplate.js
vendored
Normal file
191
core/third-party/pkijs/CertificateTemplate.js
vendored
Normal file
@@ -0,0 +1,191 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from "[MS-WCCE]: Windows Client Certificate Enrollment Protocol"
|
||||
*/
|
||||
export default class CertificateTemplate
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for CertificateTemplate class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {string}
|
||||
* @desc templateID
|
||||
*/
|
||||
this.templateID = getParametersValue(parameters, "templateID", CertificateTemplate.defaultValues("templateID"));
|
||||
|
||||
if("templateMajorVersion" in parameters)
|
||||
/**
|
||||
* @type {number}
|
||||
* @desc templateMajorVersion
|
||||
*/
|
||||
this.templateMajorVersion = getParametersValue(parameters, "templateMajorVersion", CertificateTemplate.defaultValues("templateMajorVersion"));
|
||||
|
||||
if("templateMinorVersion" in parameters)
|
||||
/**
|
||||
* @type {number}
|
||||
* @desc templateMinorVersion
|
||||
*/
|
||||
this.templateMinorVersion = getParametersValue(parameters, "templateMinorVersion", CertificateTemplate.defaultValues("templateMinorVersion"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "templateID":
|
||||
return "";
|
||||
case "templateMajorVersion":
|
||||
case "templateMinorVersion":
|
||||
return 0;
|
||||
default:
|
||||
throw new Error(`Invalid member name for CertificateTemplate class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* CertificateTemplateOID ::= SEQUENCE {
|
||||
* templateID OBJECT IDENTIFIER,
|
||||
* templateMajorVersion INTEGER (0..4294967295) OPTIONAL,
|
||||
* templateMinorVersion INTEGER (0..4294967295) OPTIONAL
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [templateID]
|
||||
* @property {string} [templateMajorVersion]
|
||||
* @property {string} [templateMinorVersion]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.ObjectIdentifier({ name: (names.templateID || "") }),
|
||||
new asn1js.Integer({
|
||||
name: (names.templateMajorVersion || ""),
|
||||
optional: true
|
||||
}),
|
||||
new asn1js.Integer({
|
||||
name: (names.templateMinorVersion || ""),
|
||||
optional: true
|
||||
}),
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"templateID",
|
||||
"templateMajorVersion",
|
||||
"templateMinorVersion"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
let asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
CertificateTemplate.schema({
|
||||
names: {
|
||||
templateID: "templateID",
|
||||
templateMajorVersion: "templateMajorVersion",
|
||||
templateMinorVersion: "templateMinorVersion"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for CertificateTemplate");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.templateID = asn1.result.templateID.valueBlock.toString();
|
||||
|
||||
if("templateMajorVersion" in asn1.result)
|
||||
this.templateMajorVersion = asn1.result.templateMajorVersion.valueBlock.valueDec;
|
||||
|
||||
if("templateMinorVersion" in asn1.result)
|
||||
this.templateMinorVersion = asn1.result.templateMinorVersion.valueBlock.valueDec;
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Create array for output sequence
|
||||
const outputArray = [];
|
||||
|
||||
outputArray.push(new asn1js.ObjectIdentifier({ value: this.templateID }));
|
||||
|
||||
if("templateMajorVersion" in this)
|
||||
outputArray.push(new asn1js.Integer({ value: this.templateMajorVersion }));
|
||||
|
||||
if("templateMinorVersion" in this)
|
||||
outputArray.push(new asn1js.Integer({ value: this.templateMinorVersion }));
|
||||
//endregion
|
||||
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: outputArray
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
const object = {
|
||||
extnID: this.templateID
|
||||
};
|
||||
|
||||
if("templateMajorVersion" in this)
|
||||
object.templateMajorVersion = this.templateMajorVersion;
|
||||
|
||||
if("templateMinorVersion" in this)
|
||||
object.templateMinorVersion = this.templateMinorVersion;
|
||||
|
||||
return object;
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
383
core/third-party/pkijs/CertificationRequest.js
vendored
Normal file
383
core/third-party/pkijs/CertificationRequest.js
vendored
Normal file
@@ -0,0 +1,383 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, bufferToHexCodes, clearProps } from "./pvutils.js";
|
||||
import { getEngine } from "./common.js";
|
||||
import PublicKeyInfo from "./PublicKeyInfo.js";
|
||||
import RelativeDistinguishedNames from "./RelativeDistinguishedNames.js";
|
||||
import AlgorithmIdentifier from "./AlgorithmIdentifier.js";
|
||||
import Attribute from "./Attribute.js";
|
||||
//**************************************************************************************
|
||||
function CertificationRequestInfo(parameters = {})
|
||||
{
|
||||
//CertificationRequestInfo ::= SEQUENCE {
|
||||
// version INTEGER { v1(0) } (v1,...),
|
||||
// subject Name,
|
||||
// subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
|
||||
// attributes [0] Attributes{{ CRIAttributes }}
|
||||
//}
|
||||
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [CertificationRequestInfo]
|
||||
* @property {string} [CertificationRequestInfoVersion]
|
||||
* @property {string} [subject]
|
||||
* @property {string} [CertificationRequestInfoAttributes]
|
||||
* @property {string} [attributes]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.CertificationRequestInfo || "CertificationRequestInfo"),
|
||||
value: [
|
||||
new asn1js.Integer({ name: (names.CertificationRequestInfoVersion || "CertificationRequestInfo.version") }),
|
||||
RelativeDistinguishedNames.schema(names.subject || {
|
||||
names: {
|
||||
blockName: "CertificationRequestInfo.subject"
|
||||
}
|
||||
}),
|
||||
PublicKeyInfo.schema({
|
||||
names: {
|
||||
blockName: "CertificationRequestInfo.subjectPublicKeyInfo"
|
||||
}
|
||||
}),
|
||||
new asn1js.Constructed({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: [
|
||||
new asn1js.Repeated({
|
||||
optional: true, // Because OpenSSL makes wrong "attributes" field
|
||||
name: (names.CertificationRequestInfoAttributes || "CertificationRequestInfo.attributes"),
|
||||
value: Attribute.schema(names.attributes || {})
|
||||
})
|
||||
]
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC2986
|
||||
*/
|
||||
export default class CertificationRequest
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for Attribute class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {ArrayBuffer}
|
||||
* @desc tbs
|
||||
*/
|
||||
this.tbs = getParametersValue(parameters, "tbs", CertificationRequest.defaultValues("tbs"));
|
||||
/**
|
||||
* @type {number}
|
||||
* @desc version
|
||||
*/
|
||||
this.version = getParametersValue(parameters, "version", CertificationRequest.defaultValues("version"));
|
||||
/**
|
||||
* @type {RelativeDistinguishedNames}
|
||||
* @desc subject
|
||||
*/
|
||||
this.subject = getParametersValue(parameters, "subject", CertificationRequest.defaultValues("subject"));
|
||||
/**
|
||||
* @type {PublicKeyInfo}
|
||||
* @desc subjectPublicKeyInfo
|
||||
*/
|
||||
this.subjectPublicKeyInfo = getParametersValue(parameters, "subjectPublicKeyInfo", CertificationRequest.defaultValues("subjectPublicKeyInfo"));
|
||||
|
||||
if("attributes" in parameters)
|
||||
/**
|
||||
* @type {Array.<Attribute>}
|
||||
* @desc attributes
|
||||
*/
|
||||
this.attributes = getParametersValue(parameters, "attributes", CertificationRequest.defaultValues("attributes"));
|
||||
|
||||
/**
|
||||
* @type {AlgorithmIdentifier}
|
||||
* @desc signatureAlgorithm
|
||||
*/
|
||||
this.signatureAlgorithm = getParametersValue(parameters, "signatureAlgorithm", CertificationRequest.defaultValues("signatureAlgorithm"));
|
||||
/**
|
||||
* @type {BitString}
|
||||
* @desc signatureAlgorithm
|
||||
*/
|
||||
this.signatureValue = getParametersValue(parameters, "signatureValue", CertificationRequest.defaultValues("signatureValue"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "tbs":
|
||||
return new ArrayBuffer(0);
|
||||
case "version":
|
||||
return 0;
|
||||
case "subject":
|
||||
return new RelativeDistinguishedNames();
|
||||
case "subjectPublicKeyInfo":
|
||||
return new PublicKeyInfo();
|
||||
case "attributes":
|
||||
return [];
|
||||
case "signatureAlgorithm":
|
||||
return new AlgorithmIdentifier();
|
||||
case "signatureValue":
|
||||
return new asn1js.BitString();
|
||||
default:
|
||||
throw new Error(`Invalid member name for CertificationRequest class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* CertificationRequest ::= SEQUENCE {
|
||||
* certificationRequestInfo CertificationRequestInfo,
|
||||
* signatureAlgorithm AlgorithmIdentifier{{ SignatureAlgorithms }},
|
||||
* signature BIT STRING
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [certificationRequestInfo]
|
||||
* @property {string} [signatureAlgorithm]
|
||||
* @property {string} [signatureValue]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
value: [
|
||||
CertificationRequestInfo(names.certificationRequestInfo || {}),
|
||||
new asn1js.Sequence({
|
||||
name: (names.signatureAlgorithm || "signatureAlgorithm"),
|
||||
value: [
|
||||
new asn1js.ObjectIdentifier(),
|
||||
new asn1js.Any({ optional: true })
|
||||
]
|
||||
}),
|
||||
new asn1js.BitString({ name: (names.signatureValue || "signatureValue") })
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"CertificationRequestInfo",
|
||||
"CertificationRequestInfo.version",
|
||||
"CertificationRequestInfo.subject",
|
||||
"CertificationRequestInfo.subjectPublicKeyInfo",
|
||||
"CertificationRequestInfo.attributes",
|
||||
"signatureAlgorithm",
|
||||
"signatureValue"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
CertificationRequest.schema()
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for CertificationRequest");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.tbs = asn1.result.CertificationRequestInfo.valueBeforeDecode;
|
||||
|
||||
this.version = asn1.result["CertificationRequestInfo.version"].valueBlock.valueDec;
|
||||
this.subject = new RelativeDistinguishedNames({ schema: asn1.result["CertificationRequestInfo.subject"] });
|
||||
this.subjectPublicKeyInfo = new PublicKeyInfo({ schema: asn1.result["CertificationRequestInfo.subjectPublicKeyInfo"] });
|
||||
if("CertificationRequestInfo.attributes" in asn1.result)
|
||||
this.attributes = Array.from(asn1.result["CertificationRequestInfo.attributes"], element => new Attribute({ schema: element }));
|
||||
|
||||
this.signatureAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.signatureAlgorithm });
|
||||
this.signatureValue = asn1.result.signatureValue;
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Aux function making ASN1js Sequence from current TBS
|
||||
* @returns {Sequence}
|
||||
*/
|
||||
encodeTBS()
|
||||
{
|
||||
//region Create array for output sequence
|
||||
const outputArray = [
|
||||
new asn1js.Integer({ value: this.version }),
|
||||
this.subject.toSchema(),
|
||||
this.subjectPublicKeyInfo.toSchema()
|
||||
];
|
||||
|
||||
if("attributes" in this)
|
||||
{
|
||||
outputArray.push(new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: Array.from(this.attributes, element => element.toSchema())
|
||||
}));
|
||||
}
|
||||
//endregion
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
value: outputArray
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema(encodeFlag = false)
|
||||
{
|
||||
//region Decode stored TBS value
|
||||
let tbsSchema;
|
||||
|
||||
if(encodeFlag === false)
|
||||
{
|
||||
if(this.tbs.byteLength === 0) // No stored TBS part
|
||||
return CertificationRequest.schema();
|
||||
|
||||
tbsSchema = asn1js.fromBER(this.tbs).result;
|
||||
}
|
||||
//endregion
|
||||
//region Create TBS schema via assembling from TBS parts
|
||||
else
|
||||
tbsSchema = this.encodeTBS();
|
||||
//endregion
|
||||
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: [
|
||||
tbsSchema,
|
||||
this.signatureAlgorithm.toSchema(),
|
||||
this.signatureValue
|
||||
]
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
const object = {
|
||||
tbs: bufferToHexCodes(this.tbs, 0, this.tbs.byteLength),
|
||||
version: this.version,
|
||||
subject: this.subject.toJSON(),
|
||||
subjectPublicKeyInfo: this.subjectPublicKeyInfo.toJSON(),
|
||||
signatureAlgorithm: this.signatureAlgorithm.toJSON(),
|
||||
signatureValue: this.signatureValue.toJSON()
|
||||
};
|
||||
|
||||
if("attributes" in this)
|
||||
object.attributes = Array.from(this.attributes, element => element.toJSON());
|
||||
|
||||
return object;
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Makes signature for currect certification request
|
||||
* @param {Object} privateKey WebCrypto private key
|
||||
* @param {string} [hashAlgorithm=SHA-1] String representing current hashing algorithm
|
||||
*/
|
||||
sign(privateKey, hashAlgorithm = "SHA-1")
|
||||
{
|
||||
//region Initial checking
|
||||
//region Get a private key from function parameter
|
||||
if(typeof privateKey === "undefined")
|
||||
return Promise.reject("Need to provide a private key for signing");
|
||||
//endregion
|
||||
//endregion
|
||||
|
||||
//region Initial variables
|
||||
let sequence = Promise.resolve();
|
||||
let parameters;
|
||||
|
||||
const engine = getEngine();
|
||||
//endregion
|
||||
|
||||
//region Get a "default parameters" for current algorithm and set correct signature algorithm
|
||||
sequence = sequence.then(() => engine.subtle.getSignatureParameters(privateKey, hashAlgorithm));
|
||||
|
||||
sequence = sequence.then(result =>
|
||||
{
|
||||
parameters = result.parameters;
|
||||
this.signatureAlgorithm = result.signatureAlgorithm;
|
||||
});
|
||||
//endregion
|
||||
|
||||
//region Create TBS data for signing
|
||||
sequence = sequence.then(() =>
|
||||
{
|
||||
this.tbs = this.encodeTBS().toBER(false);
|
||||
});
|
||||
//endregion
|
||||
|
||||
//region Signing TBS data on provided private key
|
||||
sequence = sequence.then(() => engine.subtle.signWithPrivateKey(this.tbs, privateKey, parameters));
|
||||
|
||||
sequence = sequence.then(result =>
|
||||
{
|
||||
this.signatureValue = new asn1js.BitString({ valueHex: result });
|
||||
});
|
||||
//endregion
|
||||
|
||||
return sequence;
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Verify existing certification request signature
|
||||
* @returns {*}
|
||||
*/
|
||||
verify()
|
||||
{
|
||||
return getEngine().subtle.verifyWithPublicKey(this.tbs, this.signatureValue, this.subjectPublicKeyInfo, this.signatureAlgorithm);
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Importing public key for current certificate request
|
||||
*/
|
||||
getPublicKey(parameters = null)
|
||||
{
|
||||
return getEngine().getPublicKey(this.subjectPublicKeyInfo, this.signatureAlgorithm, parameters);
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
181
core/third-party/pkijs/ContentInfo.js
vendored
Normal file
181
core/third-party/pkijs/ContentInfo.js
vendored
Normal file
@@ -0,0 +1,181 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5652
|
||||
*/
|
||||
export default class ContentInfo
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for ContentInfo class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {string}
|
||||
* @desc contentType
|
||||
*/
|
||||
this.contentType = getParametersValue(parameters, "contentType", ContentInfo.defaultValues("contentType"));
|
||||
/**
|
||||
* @type {Any}
|
||||
* @desc content
|
||||
*/
|
||||
this.content = getParametersValue(parameters, "content", ContentInfo.defaultValues("content"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "contentType":
|
||||
return "";
|
||||
case "content":
|
||||
return new asn1js.Any();
|
||||
default:
|
||||
throw new Error(`Invalid member name for ContentInfo class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Compare values with default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
* @param {*} memberValue Value to compare with default value
|
||||
*/
|
||||
static compareWithDefault(memberName, memberValue)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "contentType":
|
||||
return (memberValue === "");
|
||||
case "content":
|
||||
return (memberValue instanceof asn1js.Any);
|
||||
default:
|
||||
throw new Error(`Invalid member name for ContentInfo class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* ContentInfo ::= SEQUENCE {
|
||||
* contentType ContentType,
|
||||
* content [0] EXPLICIT ANY DEFINED BY contentType }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [contentType]
|
||||
* @property {string} [content]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
if(("optional" in names) === false)
|
||||
names.optional = false;
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || "ContentInfo"),
|
||||
optional: names.optional,
|
||||
value: [
|
||||
new asn1js.ObjectIdentifier({ name: (names.contentType || "contentType") }),
|
||||
new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: [new asn1js.Any({ name: (names.content || "content") })] // EXPLICIT ANY value
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"contentType",
|
||||
"content"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
ContentInfo.schema()
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for ContentInfo");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.contentType = asn1.result.contentType.valueBlock.toString();
|
||||
this.content = asn1.result.content;
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: [
|
||||
new asn1js.ObjectIdentifier({ value: this.contentType }),
|
||||
new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: [this.content] // EXPLICIT ANY value
|
||||
})
|
||||
]
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
const object = {
|
||||
contentType: this.contentType
|
||||
};
|
||||
|
||||
if(!(this.content instanceof asn1js.Any))
|
||||
object.content = this.content.toJSON();
|
||||
|
||||
return object;
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
2565
core/third-party/pkijs/CryptoEngine.js
vendored
Normal file
2565
core/third-party/pkijs/CryptoEngine.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
179
core/third-party/pkijs/DigestInfo.js
vendored
Normal file
179
core/third-party/pkijs/DigestInfo.js
vendored
Normal file
@@ -0,0 +1,179 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import AlgorithmIdentifier from "./AlgorithmIdentifier.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC3447
|
||||
*/
|
||||
export default class DigestInfo
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for DigestInfo class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {AlgorithmIdentifier}
|
||||
* @desc digestAlgorithm
|
||||
*/
|
||||
this.digestAlgorithm = getParametersValue(parameters, "digestAlgorithm", DigestInfo.defaultValues("digestAlgorithm"));
|
||||
/**
|
||||
* @type {OctetString}
|
||||
* @desc digest
|
||||
*/
|
||||
this.digest = getParametersValue(parameters, "digest", DigestInfo.defaultValues("digest"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "digestAlgorithm":
|
||||
return new AlgorithmIdentifier();
|
||||
case "digest":
|
||||
return new asn1js.OctetString();
|
||||
default:
|
||||
throw new Error(`Invalid member name for DigestInfo class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Compare values with default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
* @param {*} memberValue Value to compare with default value
|
||||
*/
|
||||
static compareWithDefault(memberName, memberValue)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "digestAlgorithm":
|
||||
return ((AlgorithmIdentifier.compareWithDefault("algorithmId", memberValue.algorithmId)) &&
|
||||
(("algorithmParams" in memberValue) === false));
|
||||
case "digest":
|
||||
return (memberValue.isEqual(DigestInfo.defaultValues(memberName)));
|
||||
default:
|
||||
throw new Error(`Invalid member name for DigestInfo class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* DigestInfo ::= SEQUENCE {
|
||||
* digestAlgorithm DigestAlgorithmIdentifier,
|
||||
* digest Digest }
|
||||
*
|
||||
* Digest ::= OCTET STRING
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [type]
|
||||
* @property {string} [setName]
|
||||
* @property {string} [values]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
AlgorithmIdentifier.schema(names.digestAlgorithm || {
|
||||
names: {
|
||||
blockName: "digestAlgorithm"
|
||||
}
|
||||
}),
|
||||
new asn1js.OctetString({ name: (names.digest || "digest") })
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"digestAlgorithm",
|
||||
"digest"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
DigestInfo.schema({
|
||||
names: {
|
||||
digestAlgorithm: {
|
||||
names: {
|
||||
blockName: "digestAlgorithm"
|
||||
}
|
||||
},
|
||||
digest: "digest"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for DigestInfo");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.digestAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.digestAlgorithm });
|
||||
this.digest = asn1.result.digest;
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: [
|
||||
this.digestAlgorithm.toSchema(),
|
||||
this.digest
|
||||
]
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
return {
|
||||
digestAlgorithm: this.digestAlgorithm.toJSON(),
|
||||
digest: this.digest.toJSON()
|
||||
};
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
334
core/third-party/pkijs/DistributionPoint.js
vendored
Normal file
334
core/third-party/pkijs/DistributionPoint.js
vendored
Normal file
@@ -0,0 +1,334 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import GeneralName from "./GeneralName.js";
|
||||
import RelativeDistinguishedNames from "./RelativeDistinguishedNames.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5280
|
||||
*/
|
||||
export default class DistributionPoint
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for DistributionPoint class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
* @property {Object} [distributionPoint]
|
||||
* @property {Object} [reasons]
|
||||
* @property {Object} [cRLIssuer]
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
if("distributionPoint" in parameters)
|
||||
/**
|
||||
* @type {Array.<GeneralName>}
|
||||
* @desc distributionPoint
|
||||
*/
|
||||
this.distributionPoint = getParametersValue(parameters, "distributionPoint", DistributionPoint.defaultValues("distributionPoint"));
|
||||
|
||||
if("reasons" in parameters)
|
||||
/**
|
||||
* @type {BitString}
|
||||
* @desc values
|
||||
*/
|
||||
this.reasons = getParametersValue(parameters, "reasons", DistributionPoint.defaultValues("reasons"));
|
||||
|
||||
if("cRLIssuer" in parameters)
|
||||
/**
|
||||
* @type {Array.<GeneralName>}
|
||||
* @desc cRLIssuer
|
||||
*/
|
||||
this.cRLIssuer = getParametersValue(parameters, "cRLIssuer", DistributionPoint.defaultValues("cRLIssuer"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "distributionPoint":
|
||||
return [];
|
||||
case "reasons":
|
||||
return new asn1js.BitString();
|
||||
case "cRLIssuer":
|
||||
return [];
|
||||
default:
|
||||
throw new Error(`Invalid member name for DistributionPoint class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* DistributionPoint ::= SEQUENCE {
|
||||
* distributionPoint [0] DistributionPointName OPTIONAL,
|
||||
* reasons [1] ReasonFlags OPTIONAL,
|
||||
* cRLIssuer [2] GeneralNames OPTIONAL }
|
||||
*
|
||||
* DistributionPointName ::= CHOICE {
|
||||
* fullName [0] GeneralNames,
|
||||
* nameRelativeToCRLIssuer [1] RelativeDistinguishedName }
|
||||
*
|
||||
* ReasonFlags ::= BIT STRING {
|
||||
* unused (0),
|
||||
* keyCompromise (1),
|
||||
* cACompromise (2),
|
||||
* affiliationChanged (3),
|
||||
* superseded (4),
|
||||
* cessationOfOperation (5),
|
||||
* certificateHold (6),
|
||||
* privilegeWithdrawn (7),
|
||||
* aACompromise (8) }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [distributionPoint]
|
||||
* @property {string} [distributionPointNames]
|
||||
* @property {string} [reasons]
|
||||
* @property {string} [cRLIssuer]
|
||||
* @property {string} [cRLIssuerNames]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.Constructed({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: [
|
||||
new asn1js.Choice({
|
||||
value: [
|
||||
new asn1js.Constructed({
|
||||
name: (names.distributionPoint || ""),
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: [
|
||||
new asn1js.Repeated({
|
||||
name: (names.distributionPointNames || ""),
|
||||
value: GeneralName.schema()
|
||||
})
|
||||
]
|
||||
}),
|
||||
new asn1js.Constructed({
|
||||
name: (names.distributionPoint || ""),
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 1 // [1]
|
||||
},
|
||||
value: RelativeDistinguishedNames.schema().valueBlock.value
|
||||
})
|
||||
]
|
||||
})
|
||||
]
|
||||
}),
|
||||
new asn1js.Primitive({
|
||||
name: (names.reasons || ""),
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 1 // [1]
|
||||
}
|
||||
}), // IMPLICIT bitstring value
|
||||
new asn1js.Constructed({
|
||||
name: (names.cRLIssuer || ""),
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 2 // [2]
|
||||
},
|
||||
value: [
|
||||
new asn1js.Repeated({
|
||||
name: (names.cRLIssuerNames || ""),
|
||||
value: GeneralName.schema()
|
||||
})
|
||||
]
|
||||
}) // IMPLICIT bitstring value
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"distributionPoint",
|
||||
"distributionPointNames",
|
||||
"reasons",
|
||||
"cRLIssuer",
|
||||
"cRLIssuerNames"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
DistributionPoint.schema({
|
||||
names: {
|
||||
distributionPoint: "distributionPoint",
|
||||
distributionPointNames: "distributionPointNames",
|
||||
reasons: "reasons",
|
||||
cRLIssuer: "cRLIssuer",
|
||||
cRLIssuerNames: "cRLIssuerNames"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for DistributionPoint");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
if("distributionPoint" in asn1.result)
|
||||
{
|
||||
if(asn1.result.distributionPoint.idBlock.tagNumber === 0) // GENERAL_NAMES variant
|
||||
this.distributionPoint = Array.from(asn1.result.distributionPointNames, element => new GeneralName({ schema: element }));
|
||||
|
||||
if(asn1.result.distributionPoint.idBlock.tagNumber === 1) // RDN variant
|
||||
{
|
||||
this.distributionPoint = new RelativeDistinguishedNames({
|
||||
schema: new asn1js.Sequence({
|
||||
value: asn1.result.distributionPoint.valueBlock.value
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if("reasons" in asn1.result)
|
||||
this.reasons = new asn1js.BitString({ valueHex: asn1.result.reasons.valueBlock.valueHex });
|
||||
|
||||
if("cRLIssuer" in asn1.result)
|
||||
this.cRLIssuer = Array.from(asn1.result.cRLIssuerNames, element => new GeneralName({ schema: element }));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Create array for output sequence
|
||||
const outputArray = [];
|
||||
|
||||
if("distributionPoint" in this)
|
||||
{
|
||||
let internalValue;
|
||||
|
||||
if(this.distributionPoint instanceof Array)
|
||||
{
|
||||
internalValue = new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: Array.from(this.distributionPoint, element => element.toSchema())
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
internalValue = new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 1 // [1]
|
||||
},
|
||||
value: [this.distributionPoint.toSchema()]
|
||||
});
|
||||
}
|
||||
|
||||
outputArray.push(new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: [internalValue]
|
||||
}));
|
||||
}
|
||||
|
||||
if("reasons" in this)
|
||||
{
|
||||
outputArray.push(new asn1js.Primitive({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 1 // [1]
|
||||
},
|
||||
valueHex: this.reasons.valueBlock.valueHex
|
||||
}));
|
||||
}
|
||||
|
||||
if("cRLIssuer" in this)
|
||||
{
|
||||
outputArray.push(new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 2 // [2]
|
||||
},
|
||||
value: Array.from(this.cRLIssuer, element => element.toSchema())
|
||||
}));
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: outputArray
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
const object = {};
|
||||
|
||||
if("distributionPoint" in this)
|
||||
{
|
||||
if(this.distributionPoint instanceof Array)
|
||||
object.distributionPoint = Array.from(this.distributionPoint, element => element.toJSON());
|
||||
else
|
||||
object.distributionPoint = this.distributionPoint.toJSON();
|
||||
}
|
||||
|
||||
if("reasons" in this)
|
||||
object.reasons = this.reasons.toJSON();
|
||||
|
||||
if("cRLIssuer" in this)
|
||||
object.cRLIssuer = Array.from(this.cRLIssuer, element => element.toJSON());
|
||||
|
||||
return object;
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
233
core/third-party/pkijs/ECCCMSSharedInfo.js
vendored
Normal file
233
core/third-party/pkijs/ECCCMSSharedInfo.js
vendored
Normal file
@@ -0,0 +1,233 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import AlgorithmIdentifier from "./AlgorithmIdentifier.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC6318
|
||||
*/
|
||||
export default class ECCCMSSharedInfo
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for ECCCMSSharedInfo class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {AlgorithmIdentifier}
|
||||
* @desc keyInfo
|
||||
*/
|
||||
this.keyInfo = getParametersValue(parameters, "keyInfo", ECCCMSSharedInfo.defaultValues("keyInfo"));
|
||||
|
||||
if("entityUInfo" in parameters)
|
||||
/**
|
||||
* @type {OctetString}
|
||||
* @desc entityUInfo
|
||||
*/
|
||||
this.entityUInfo = getParametersValue(parameters, "entityUInfo", ECCCMSSharedInfo.defaultValues("entityUInfo"));
|
||||
|
||||
/**
|
||||
* @type {OctetString}
|
||||
* @desc suppPubInfo
|
||||
*/
|
||||
this.suppPubInfo = getParametersValue(parameters, "suppPubInfo", ECCCMSSharedInfo.defaultValues("suppPubInfo"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "keyInfo":
|
||||
return new AlgorithmIdentifier();
|
||||
case "entityUInfo":
|
||||
return new asn1js.OctetString();
|
||||
case "suppPubInfo":
|
||||
return new asn1js.OctetString();
|
||||
default:
|
||||
throw new Error(`Invalid member name for ECCCMSSharedInfo class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Compare values with default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
* @param {*} memberValue Value to compare with default value
|
||||
*/
|
||||
static compareWithDefault(memberName, memberValue)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "keyInfo":
|
||||
case "entityUInfo":
|
||||
case "suppPubInfo":
|
||||
return (memberValue.isEqual(ECCCMSSharedInfo.defaultValues(memberName)));
|
||||
default:
|
||||
throw new Error(`Invalid member name for ECCCMSSharedInfo class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* ECC-CMS-SharedInfo ::= SEQUENCE {
|
||||
* keyInfo AlgorithmIdentifier,
|
||||
* entityUInfo [0] EXPLICIT OCTET STRING OPTIONAL,
|
||||
* suppPubInfo [2] EXPLICIT OCTET STRING }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [keyInfo]
|
||||
* @property {string} [entityUInfo]
|
||||
* @property {string} [suppPubInfo]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
AlgorithmIdentifier.schema(names.keyInfo || {}),
|
||||
new asn1js.Constructed({
|
||||
name: (names.entityUInfo || ""),
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
optional: true,
|
||||
value: [new asn1js.OctetString()]
|
||||
}),
|
||||
new asn1js.Constructed({
|
||||
name: (names.suppPubInfo || ""),
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 2 // [2]
|
||||
},
|
||||
value: [new asn1js.OctetString()]
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"keyInfo",
|
||||
"entityUInfo",
|
||||
"suppPubInfo"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
ECCCMSSharedInfo.schema({
|
||||
names: {
|
||||
keyInfo: {
|
||||
names: {
|
||||
blockName: "keyInfo"
|
||||
}
|
||||
},
|
||||
entityUInfo: "entityUInfo",
|
||||
suppPubInfo: "suppPubInfo"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for ECCCMSSharedInfo");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.keyInfo = new AlgorithmIdentifier({ schema: asn1.result.keyInfo });
|
||||
|
||||
if("entityUInfo" in asn1.result)
|
||||
this.entityUInfo = asn1.result.entityUInfo.valueBlock.value[0];
|
||||
|
||||
this.suppPubInfo = asn1.result.suppPubInfo.valueBlock.value[0];
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Create output array for sequence
|
||||
const outputArray = [];
|
||||
|
||||
outputArray.push(this.keyInfo.toSchema());
|
||||
|
||||
if("entityUInfo" in this)
|
||||
{
|
||||
outputArray.push(new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: [this.entityUInfo]
|
||||
}));
|
||||
}
|
||||
|
||||
outputArray.push(new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 2 // [2]
|
||||
},
|
||||
value: [this.suppPubInfo]
|
||||
}));
|
||||
//endregion
|
||||
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return new asn1js.Sequence({
|
||||
value: outputArray
|
||||
});
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
const _object = {
|
||||
keyInfo: this.keyInfo.toJSON()
|
||||
};
|
||||
|
||||
if("entityUInfo" in this)
|
||||
_object.entityUInfo = this.entityUInfo.toJSON();
|
||||
|
||||
_object.suppPubInfo = this.suppPubInfo.toJSON();
|
||||
|
||||
return _object;
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
344
core/third-party/pkijs/ECPrivateKey.js
vendored
Normal file
344
core/third-party/pkijs/ECPrivateKey.js
vendored
Normal file
@@ -0,0 +1,344 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, toBase64, arrayBufferToString, stringToArrayBuffer, fromBase64, clearProps } from "./pvutils.js";
|
||||
import ECPublicKey from "./ECPublicKey.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5915
|
||||
*/
|
||||
export default class ECPrivateKey
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for ECPrivateKey class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {number}
|
||||
* @desc version
|
||||
*/
|
||||
this.version = getParametersValue(parameters, "version", ECPrivateKey.defaultValues("version"));
|
||||
/**
|
||||
* @type {OctetString}
|
||||
* @desc privateKey
|
||||
*/
|
||||
this.privateKey = getParametersValue(parameters, "privateKey", ECPrivateKey.defaultValues("privateKey"));
|
||||
|
||||
if("namedCurve" in parameters)
|
||||
/**
|
||||
* @type {string}
|
||||
* @desc namedCurve
|
||||
*/
|
||||
this.namedCurve = getParametersValue(parameters, "namedCurve", ECPrivateKey.defaultValues("namedCurve"));
|
||||
|
||||
if("publicKey" in parameters)
|
||||
/**
|
||||
* @type {ECPublicKey}
|
||||
* @desc publicKey
|
||||
*/
|
||||
this.publicKey = getParametersValue(parameters, "publicKey", ECPrivateKey.defaultValues("publicKey"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
//region If input argument array contains "json" for this object
|
||||
if("json" in parameters)
|
||||
this.fromJSON(parameters.json);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "version":
|
||||
return 1;
|
||||
case "privateKey":
|
||||
return new asn1js.OctetString();
|
||||
case "namedCurve":
|
||||
return "";
|
||||
case "publicKey":
|
||||
return new ECPublicKey();
|
||||
default:
|
||||
throw new Error(`Invalid member name for ECCPrivateKey class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Compare values with default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
* @param {*} memberValue Value to compare with default value
|
||||
*/
|
||||
static compareWithDefault(memberName, memberValue)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "version":
|
||||
return (memberValue === ECPrivateKey.defaultValues(memberName));
|
||||
case "privateKey":
|
||||
return (memberValue.isEqual(ECPrivateKey.defaultValues(memberName)));
|
||||
case "namedCurve":
|
||||
return (memberValue === "");
|
||||
case "publicKey":
|
||||
return ((ECPublicKey.compareWithDefault("namedCurve", memberValue.namedCurve)) &&
|
||||
(ECPublicKey.compareWithDefault("x", memberValue.x)) &&
|
||||
(ECPublicKey.compareWithDefault("y", memberValue.y)));
|
||||
default:
|
||||
throw new Error(`Invalid member name for ECCPrivateKey class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* ECPrivateKey ::= SEQUENCE {
|
||||
* version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
|
||||
* privateKey OCTET STRING,
|
||||
* parameters [0] ECParameters {{ NamedCurve }} OPTIONAL,
|
||||
* publicKey [1] BIT STRING OPTIONAL
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [version]
|
||||
* @property {string} [privateKey]
|
||||
* @property {string} [namedCurve]
|
||||
* @property {string} [publicKey]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.Integer({ name: (names.version || "") }),
|
||||
new asn1js.OctetString({ name: (names.privateKey || "") }),
|
||||
new asn1js.Constructed({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: [
|
||||
new asn1js.ObjectIdentifier({ name: (names.namedCurve || "") })
|
||||
]
|
||||
}),
|
||||
new asn1js.Constructed({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 1 // [1]
|
||||
},
|
||||
value: [
|
||||
new asn1js.BitString({ name: (names.publicKey || "") })
|
||||
]
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"version",
|
||||
"privateKey",
|
||||
"namedCurve",
|
||||
"publicKey"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
ECPrivateKey.schema({
|
||||
names: {
|
||||
version: "version",
|
||||
privateKey: "privateKey",
|
||||
namedCurve: "namedCurve",
|
||||
publicKey: "publicKey"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for ECPrivateKey");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.version = asn1.result.version.valueBlock.valueDec;
|
||||
this.privateKey = asn1.result.privateKey;
|
||||
|
||||
if("namedCurve" in asn1.result)
|
||||
this.namedCurve = asn1.result.namedCurve.valueBlock.toString();
|
||||
|
||||
if("publicKey" in asn1.result)
|
||||
{
|
||||
const publicKeyData = { schema: asn1.result.publicKey.valueBlock.valueHex };
|
||||
if("namedCurve" in this)
|
||||
publicKeyData.namedCurve = this.namedCurve;
|
||||
|
||||
this.publicKey = new ECPublicKey(publicKeyData);
|
||||
}
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
const outputArray = [
|
||||
new asn1js.Integer({ value: this.version }),
|
||||
this.privateKey
|
||||
];
|
||||
|
||||
if("namedCurve" in this)
|
||||
{
|
||||
outputArray.push(new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: [
|
||||
new asn1js.ObjectIdentifier({ value: this.namedCurve })
|
||||
]
|
||||
}));
|
||||
}
|
||||
|
||||
if("publicKey" in this)
|
||||
{
|
||||
outputArray.push(new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 1 // [1]
|
||||
},
|
||||
value: [
|
||||
new asn1js.BitString({ valueHex: this.publicKey.toSchema().toBER(false) })
|
||||
]
|
||||
}));
|
||||
}
|
||||
|
||||
return new asn1js.Sequence({
|
||||
value: outputArray
|
||||
});
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
if((("namedCurve" in this) === false) || (ECPrivateKey.compareWithDefault("namedCurve", this.namedCurve)))
|
||||
throw new Error("Not enough information for making JSON: absent \"namedCurve\" value");
|
||||
|
||||
let crvName = "";
|
||||
|
||||
switch(this.namedCurve)
|
||||
{
|
||||
case "1.2.840.10045.3.1.7": // P-256
|
||||
crvName = "P-256";
|
||||
break;
|
||||
case "1.3.132.0.34": // P-384
|
||||
crvName = "P-384";
|
||||
break;
|
||||
case "1.3.132.0.35": // P-521
|
||||
crvName = "P-521";
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
const privateKeyJSON = {
|
||||
crv: crvName,
|
||||
d: toBase64(arrayBufferToString(this.privateKey.valueBlock.valueHex), true, true, false)
|
||||
};
|
||||
|
||||
if("publicKey" in this)
|
||||
{
|
||||
const publicKeyJSON = this.publicKey.toJSON();
|
||||
|
||||
privateKeyJSON.x = publicKeyJSON.x;
|
||||
privateKeyJSON.y = publicKeyJSON.y;
|
||||
}
|
||||
|
||||
return privateKeyJSON;
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert JSON value into current object
|
||||
* @param {Object} json
|
||||
*/
|
||||
fromJSON(json)
|
||||
{
|
||||
let coodinateLength = 0;
|
||||
|
||||
if("crv" in json)
|
||||
{
|
||||
switch(json.crv.toUpperCase())
|
||||
{
|
||||
case "P-256":
|
||||
this.namedCurve = "1.2.840.10045.3.1.7";
|
||||
coodinateLength = 32;
|
||||
break;
|
||||
case "P-384":
|
||||
this.namedCurve = "1.3.132.0.34";
|
||||
coodinateLength = 48;
|
||||
break;
|
||||
case "P-521":
|
||||
this.namedCurve = "1.3.132.0.35";
|
||||
coodinateLength = 66;
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
else
|
||||
throw new Error("Absent mandatory parameter \"crv\"");
|
||||
|
||||
if("d" in json)
|
||||
{
|
||||
const convertBuffer = stringToArrayBuffer(fromBase64(json.d, true));
|
||||
|
||||
if(convertBuffer.byteLength < coodinateLength)
|
||||
{
|
||||
const buffer = new ArrayBuffer(coodinateLength);
|
||||
const view = new Uint8Array(buffer);
|
||||
const convertBufferView = new Uint8Array(convertBuffer);
|
||||
view.set(convertBufferView, 1);
|
||||
|
||||
this.privateKey = new asn1js.OctetString({ valueHex: buffer });
|
||||
}
|
||||
else
|
||||
this.privateKey = new asn1js.OctetString({ valueHex: convertBuffer.slice(0, coodinateLength) });
|
||||
}
|
||||
else
|
||||
throw new Error("Absent mandatory parameter \"d\"");
|
||||
|
||||
if(("x" in json) && ("y" in json))
|
||||
this.publicKey = new ECPublicKey({ json });
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
242
core/third-party/pkijs/ECPublicKey.js
vendored
Normal file
242
core/third-party/pkijs/ECPublicKey.js
vendored
Normal file
@@ -0,0 +1,242 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, utilConcatBuf, isEqualBuffer, toBase64, fromBase64, arrayBufferToString, stringToArrayBuffer } from "./pvutils.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5480
|
||||
*/
|
||||
export default class ECPublicKey
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for ECCPublicKey class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {ArrayBuffer}
|
||||
* @desc type
|
||||
*/
|
||||
this.x = getParametersValue(parameters, "x", ECPublicKey.defaultValues("x"));
|
||||
/**
|
||||
* @type {ArrayBuffer}
|
||||
* @desc values
|
||||
*/
|
||||
this.y = getParametersValue(parameters, "y", ECPublicKey.defaultValues("y"));
|
||||
/**
|
||||
* @type {string}
|
||||
* @desc namedCurve
|
||||
*/
|
||||
this.namedCurve = getParametersValue(parameters, "namedCurve", ECPublicKey.defaultValues("namedCurve"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
//region If input argument array contains "json" for this object
|
||||
if("json" in parameters)
|
||||
this.fromJSON(parameters.json);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "x":
|
||||
case "y":
|
||||
return new ArrayBuffer(0);
|
||||
case "namedCurve":
|
||||
return "";
|
||||
default:
|
||||
throw new Error(`Invalid member name for ECCPublicKey class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Compare values with default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
* @param {*} memberValue Value to compare with default value
|
||||
*/
|
||||
static compareWithDefault(memberName, memberValue)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "x":
|
||||
case "y":
|
||||
return (isEqualBuffer(memberValue, ECPublicKey.defaultValues(memberName)));
|
||||
case "namedCurve":
|
||||
return (memberValue === "");
|
||||
default:
|
||||
throw new Error(`Invalid member name for ECCPublicKey class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
return new asn1js.RawData();
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert ArrayBuffer into current class
|
||||
* @param {!ArrayBuffer} schema Special case: schema is an ArrayBuffer
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Check the schema is valid
|
||||
if((schema instanceof ArrayBuffer) === false)
|
||||
throw new Error("Object's schema was not verified against input data for ECPublicKey");
|
||||
|
||||
const view = new Uint8Array(schema);
|
||||
if(view[0] !== 0x04)
|
||||
throw new Error("Object's schema was not verified against input data for ECPublicKey");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
let coordinateLength;
|
||||
|
||||
switch(this.namedCurve)
|
||||
{
|
||||
case "1.2.840.10045.3.1.7": // P-256
|
||||
coordinateLength = 32;
|
||||
break;
|
||||
case "1.3.132.0.34": // P-384
|
||||
coordinateLength = 48;
|
||||
break;
|
||||
case "1.3.132.0.35": // P-521
|
||||
coordinateLength = 66;
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Incorrect curve OID: ${this.namedCurve}`);
|
||||
}
|
||||
|
||||
if(schema.byteLength !== (coordinateLength * 2 + 1))
|
||||
throw new Error("Object's schema was not verified against input data for ECPublicKey");
|
||||
|
||||
this.x = schema.slice(1, coordinateLength + 1);
|
||||
this.y = schema.slice(1 + coordinateLength, coordinateLength * 2 + 1);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
return new asn1js.RawData({ data: utilConcatBuf(
|
||||
(new Uint8Array([0x04])).buffer,
|
||||
this.x,
|
||||
this.y
|
||||
)
|
||||
});
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
let crvName = "";
|
||||
|
||||
switch(this.namedCurve)
|
||||
{
|
||||
case "1.2.840.10045.3.1.7": // P-256
|
||||
crvName = "P-256";
|
||||
break;
|
||||
case "1.3.132.0.34": // P-384
|
||||
crvName = "P-384";
|
||||
break;
|
||||
case "1.3.132.0.35": // P-521
|
||||
crvName = "P-521";
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
return {
|
||||
crv: crvName,
|
||||
x: toBase64(arrayBufferToString(this.x), true, true, false),
|
||||
y: toBase64(arrayBufferToString(this.y), true, true, false)
|
||||
};
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert JSON value into current object
|
||||
* @param {Object} json
|
||||
*/
|
||||
fromJSON(json)
|
||||
{
|
||||
let coodinateLength = 0;
|
||||
|
||||
if("crv" in json)
|
||||
{
|
||||
switch(json.crv.toUpperCase())
|
||||
{
|
||||
case "P-256":
|
||||
this.namedCurve = "1.2.840.10045.3.1.7";
|
||||
coodinateLength = 32;
|
||||
break;
|
||||
case "P-384":
|
||||
this.namedCurve = "1.3.132.0.34";
|
||||
coodinateLength = 48;
|
||||
break;
|
||||
case "P-521":
|
||||
this.namedCurve = "1.3.132.0.35";
|
||||
coodinateLength = 66;
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
else
|
||||
throw new Error("Absent mandatory parameter \"crv\"");
|
||||
|
||||
if("x" in json)
|
||||
{
|
||||
const convertBuffer = stringToArrayBuffer(fromBase64(json.x, true));
|
||||
|
||||
if(convertBuffer.byteLength < coodinateLength)
|
||||
{
|
||||
this.x = new ArrayBuffer(coodinateLength);
|
||||
const view = new Uint8Array(this.x);
|
||||
const convertBufferView = new Uint8Array(convertBuffer);
|
||||
view.set(convertBufferView, 1);
|
||||
}
|
||||
else
|
||||
this.x = convertBuffer.slice(0, coodinateLength);
|
||||
}
|
||||
else
|
||||
throw new Error("Absent mandatory parameter \"x\"");
|
||||
|
||||
if("y" in json)
|
||||
{
|
||||
const convertBuffer = stringToArrayBuffer(fromBase64(json.y, true));
|
||||
|
||||
if(convertBuffer.byteLength < coodinateLength)
|
||||
{
|
||||
this.y = new ArrayBuffer(coodinateLength);
|
||||
const view = new Uint8Array(this.y);
|
||||
const convertBufferView = new Uint8Array(convertBuffer);
|
||||
view.set(convertBufferView, 1);
|
||||
}
|
||||
else
|
||||
this.y = convertBuffer.slice(0, coodinateLength);
|
||||
}
|
||||
else
|
||||
throw new Error("Absent mandatory parameter \"y\"");
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
243
core/third-party/pkijs/EncapsulatedContentInfo.js
vendored
Normal file
243
core/third-party/pkijs/EncapsulatedContentInfo.js
vendored
Normal file
@@ -0,0 +1,243 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5652
|
||||
*/
|
||||
export default class EncapsulatedContentInfo
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for EncapsulatedContentInfo class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {string}
|
||||
* @desc eContentType
|
||||
*/
|
||||
this.eContentType = getParametersValue(parameters, "eContentType", EncapsulatedContentInfo.defaultValues("eContentType"));
|
||||
|
||||
if("eContent" in parameters)
|
||||
{
|
||||
/**
|
||||
* @type {OctetString}
|
||||
* @desc eContent
|
||||
*/
|
||||
this.eContent = getParametersValue(parameters, "eContent", EncapsulatedContentInfo.defaultValues("eContent"));
|
||||
if((this.eContent.idBlock.tagClass === 1) &&
|
||||
(this.eContent.idBlock.tagNumber === 4))
|
||||
{
|
||||
//region Divide OCTETSTRING value down to small pieces
|
||||
if(this.eContent.idBlock.isConstructed === false)
|
||||
{
|
||||
const constrString = new asn1js.OctetString({
|
||||
idBlock: { isConstructed: true },
|
||||
isConstructed: true
|
||||
});
|
||||
|
||||
let offset = 0;
|
||||
let length = this.eContent.valueBlock.valueHex.byteLength;
|
||||
|
||||
while(length > 0)
|
||||
{
|
||||
const pieceView = new Uint8Array(this.eContent.valueBlock.valueHex, offset, ((offset + 65536) > this.eContent.valueBlock.valueHex.byteLength) ? (this.eContent.valueBlock.valueHex.byteLength - offset) : 65536);
|
||||
const _array = new ArrayBuffer(pieceView.length);
|
||||
const _view = new Uint8Array(_array);
|
||||
|
||||
for(let i = 0; i < _view.length; i++)
|
||||
_view[i] = pieceView[i];
|
||||
|
||||
constrString.valueBlock.value.push(new asn1js.OctetString({ valueHex: _array }));
|
||||
|
||||
length -= pieceView.length;
|
||||
offset += pieceView.length;
|
||||
}
|
||||
|
||||
this.eContent = constrString;
|
||||
}
|
||||
//endregion
|
||||
}
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "eContentType":
|
||||
return "";
|
||||
case "eContent":
|
||||
return new asn1js.OctetString();
|
||||
default:
|
||||
throw new Error(`Invalid member name for EncapsulatedContentInfo class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Compare values with default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
* @param {*} memberValue Value to compare with default value
|
||||
*/
|
||||
static compareWithDefault(memberName, memberValue)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "eContentType":
|
||||
return (memberValue === "");
|
||||
case "eContent":
|
||||
{
|
||||
if((memberValue.idBlock.tagClass === 1) && (memberValue.idBlock.tagNumber === 4))
|
||||
return (memberValue.isEqual(EncapsulatedContentInfo.defaultValues("eContent")));
|
||||
|
||||
return false;
|
||||
}
|
||||
default:
|
||||
throw new Error(`Invalid member name for EncapsulatedContentInfo class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* EncapsulatedContentInfo ::= SEQUENCE {
|
||||
* eContentType ContentType,
|
||||
* eContent [0] EXPLICIT OCTET STRING OPTIONAL } * Changed it to ANY, as in PKCS#7
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [type]
|
||||
* @property {string} [setName]
|
||||
* @property {string} [values]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.ObjectIdentifier({ name: (names.eContentType || "") }),
|
||||
new asn1js.Constructed({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: [
|
||||
new asn1js.Any({ name: (names.eContent || "") }) // In order to aling this with PKCS#7 and CMS as well
|
||||
]
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"eContentType",
|
||||
"eContent"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
EncapsulatedContentInfo.schema({
|
||||
names: {
|
||||
eContentType: "eContentType",
|
||||
eContent: "eContent"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for EncapsulatedContentInfo");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.eContentType = asn1.result.eContentType.valueBlock.toString();
|
||||
if("eContent" in asn1.result)
|
||||
this.eContent = asn1.result.eContent;
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Create array for output sequence
|
||||
const outputArray = [];
|
||||
|
||||
outputArray.push(new asn1js.ObjectIdentifier({ value: this.eContentType }));
|
||||
if("eContent" in this)
|
||||
{
|
||||
if(EncapsulatedContentInfo.compareWithDefault("eContent", this.eContent) === false)
|
||||
{
|
||||
outputArray.push(new asn1js.Constructed({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: [this.eContent]
|
||||
}));
|
||||
}
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: outputArray
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
const _object = {
|
||||
eContentType: this.eContentType
|
||||
};
|
||||
|
||||
if("eContent" in this)
|
||||
{
|
||||
if(EncapsulatedContentInfo.compareWithDefault("eContent", this.eContent) === false)
|
||||
_object.eContent = this.eContent.toJSON();
|
||||
}
|
||||
|
||||
return _object;
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
287
core/third-party/pkijs/EncryptedContentInfo.js
vendored
Normal file
287
core/third-party/pkijs/EncryptedContentInfo.js
vendored
Normal file
@@ -0,0 +1,287 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import AlgorithmIdentifier from "./AlgorithmIdentifier.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5652
|
||||
*/
|
||||
export default class EncryptedContentInfo
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for EncryptedContentInfo class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {string}
|
||||
* @desc contentType
|
||||
*/
|
||||
this.contentType = getParametersValue(parameters, "contentType", EncryptedContentInfo.defaultValues("contentType"));
|
||||
/**
|
||||
* @type {AlgorithmIdentifier}
|
||||
* @desc contentEncryptionAlgorithm
|
||||
*/
|
||||
this.contentEncryptionAlgorithm = getParametersValue(parameters, "contentEncryptionAlgorithm", EncryptedContentInfo.defaultValues("contentEncryptionAlgorithm"));
|
||||
|
||||
if("encryptedContent" in parameters)
|
||||
{
|
||||
/**
|
||||
* @type {OctetString}
|
||||
* @desc encryptedContent (!!!) could be contructive or primitive value (!!!)
|
||||
*/
|
||||
this.encryptedContent = parameters.encryptedContent;
|
||||
|
||||
if((this.encryptedContent.idBlock.tagClass === 1) &&
|
||||
(this.encryptedContent.idBlock.tagNumber === 4))
|
||||
{
|
||||
//region Divide OCTETSTRING value down to small pieces
|
||||
if(this.encryptedContent.idBlock.isConstructed === false)
|
||||
{
|
||||
const constrString = new asn1js.OctetString({
|
||||
idBlock: { isConstructed: true },
|
||||
isConstructed: true
|
||||
});
|
||||
|
||||
let offset = 0;
|
||||
let length = this.encryptedContent.valueBlock.valueHex.byteLength;
|
||||
|
||||
while(length > 0)
|
||||
{
|
||||
const pieceView = new Uint8Array(this.encryptedContent.valueBlock.valueHex, offset, ((offset + 1024) > this.encryptedContent.valueBlock.valueHex.byteLength) ? (this.encryptedContent.valueBlock.valueHex.byteLength - offset) : 1024);
|
||||
const _array = new ArrayBuffer(pieceView.length);
|
||||
const _view = new Uint8Array(_array);
|
||||
|
||||
for(let i = 0; i < _view.length; i++)
|
||||
_view[i] = pieceView[i];
|
||||
|
||||
constrString.valueBlock.value.push(new asn1js.OctetString({ valueHex: _array }));
|
||||
|
||||
length -= pieceView.length;
|
||||
offset += pieceView.length;
|
||||
}
|
||||
|
||||
this.encryptedContent = constrString;
|
||||
}
|
||||
//endregion
|
||||
}
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "contentType":
|
||||
return "";
|
||||
case "contentEncryptionAlgorithm":
|
||||
return new AlgorithmIdentifier();
|
||||
case "encryptedContent":
|
||||
return new asn1js.OctetString();
|
||||
default:
|
||||
throw new Error(`Invalid member name for EncryptedContentInfo class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Compare values with default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
* @param {*} memberValue Value to compare with default value
|
||||
*/
|
||||
static compareWithDefault(memberName, memberValue)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "contentType":
|
||||
return (memberValue === "");
|
||||
case "contentEncryptionAlgorithm":
|
||||
return ((memberValue.algorithmId === "") && (("algorithmParams" in memberValue) === false));
|
||||
case "encryptedContent":
|
||||
return (memberValue.isEqual(EncryptedContentInfo.defaultValues(memberName)));
|
||||
default:
|
||||
throw new Error(`Invalid member name for EncryptedContentInfo class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* EncryptedContentInfo ::= SEQUENCE {
|
||||
* contentType ContentType,
|
||||
* contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
|
||||
* encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL }
|
||||
*
|
||||
* Comment: Strange, but modern crypto engines create "encryptedContent" as "[0] EXPLICIT EncryptedContent"
|
||||
*
|
||||
* EncryptedContent ::= OCTET STRING
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [contentType]
|
||||
* @property {string} [contentEncryptionAlgorithm]
|
||||
* @property {string} [encryptedContent]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.ObjectIdentifier({ name: (names.contentType || "") }),
|
||||
AlgorithmIdentifier.schema(names.contentEncryptionAlgorithm || {}),
|
||||
// The CHOICE we need because "EncryptedContent" could have either "constructive"
|
||||
// or "primitive" form of encoding and we need to handle both variants
|
||||
new asn1js.Choice({
|
||||
value: [
|
||||
new asn1js.Constructed({
|
||||
name: (names.encryptedContent || ""),
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: [
|
||||
new asn1js.Repeated({
|
||||
value: new asn1js.OctetString()
|
||||
})
|
||||
]
|
||||
}),
|
||||
new asn1js.Primitive({
|
||||
name: (names.encryptedContent || ""),
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
}
|
||||
})
|
||||
]
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"contentType",
|
||||
"contentEncryptionAlgorithm",
|
||||
"encryptedContent"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
EncryptedContentInfo.schema({
|
||||
names: {
|
||||
contentType: "contentType",
|
||||
contentEncryptionAlgorithm: {
|
||||
names: {
|
||||
blockName: "contentEncryptionAlgorithm"
|
||||
}
|
||||
},
|
||||
encryptedContent: "encryptedContent"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for EncryptedContentInfo");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.contentType = asn1.result.contentType.valueBlock.toString();
|
||||
this.contentEncryptionAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.contentEncryptionAlgorithm });
|
||||
|
||||
if("encryptedContent" in asn1.result)
|
||||
{
|
||||
this.encryptedContent = asn1.result.encryptedContent;
|
||||
|
||||
this.encryptedContent.idBlock.tagClass = 1; // UNIVERSAL
|
||||
this.encryptedContent.idBlock.tagNumber = 4; // OCTETSTRING (!!!) The value still has instance of "in_window.org.pkijs.asn1.ASN1_CONSTRUCTED / ASN1_PRIMITIVE"
|
||||
}
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Create array for output sequence
|
||||
const sequenceLengthBlock = {
|
||||
isIndefiniteForm: false
|
||||
};
|
||||
|
||||
const outputArray = [];
|
||||
|
||||
outputArray.push(new asn1js.ObjectIdentifier({ value: this.contentType }));
|
||||
outputArray.push(this.contentEncryptionAlgorithm.toSchema());
|
||||
|
||||
if("encryptedContent" in this)
|
||||
{
|
||||
sequenceLengthBlock.isIndefiniteForm = this.encryptedContent.idBlock.isConstructed;
|
||||
|
||||
const encryptedValue = this.encryptedContent;
|
||||
|
||||
encryptedValue.idBlock.tagClass = 3; // CONTEXT-SPECIFIC
|
||||
encryptedValue.idBlock.tagNumber = 0; // [0]
|
||||
|
||||
encryptedValue.lenBlock.isIndefiniteForm = this.encryptedContent.idBlock.isConstructed;
|
||||
|
||||
outputArray.push(encryptedValue);
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
lenBlock: sequenceLengthBlock,
|
||||
value: outputArray
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
const _object = {
|
||||
contentType: this.contentType,
|
||||
contentEncryptionAlgorithm: this.contentEncryptionAlgorithm.toJSON()
|
||||
};
|
||||
|
||||
if("encryptedContent" in this)
|
||||
_object.encryptedContent = this.encryptedContent.toJSON();
|
||||
|
||||
return _object;
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
287
core/third-party/pkijs/EncryptedData.js
vendored
Normal file
287
core/third-party/pkijs/EncryptedData.js
vendored
Normal file
@@ -0,0 +1,287 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import { getEngine } from "./common.js";
|
||||
import EncryptedContentInfo from "./EncryptedContentInfo.js";
|
||||
import Attribute from "./Attribute.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5652
|
||||
*/
|
||||
export default class EncryptedData
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for EncryptedData class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {number}
|
||||
* @desc version
|
||||
*/
|
||||
this.version = getParametersValue(parameters, "version", EncryptedData.defaultValues("version"));
|
||||
/**
|
||||
* @type {EncryptedContentInfo}
|
||||
* @desc encryptedContentInfo
|
||||
*/
|
||||
this.encryptedContentInfo = getParametersValue(parameters, "encryptedContentInfo", EncryptedData.defaultValues("encryptedContentInfo"));
|
||||
|
||||
if("unprotectedAttrs" in parameters)
|
||||
/**
|
||||
* @type {Array.<Attribute>}
|
||||
* @desc unprotectedAttrs
|
||||
*/
|
||||
this.unprotectedAttrs = getParametersValue(parameters, "unprotectedAttrs", EncryptedData.defaultValues("unprotectedAttrs"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "version":
|
||||
return 0;
|
||||
case "encryptedContentInfo":
|
||||
return new EncryptedContentInfo();
|
||||
case "unprotectedAttrs":
|
||||
return [];
|
||||
default:
|
||||
throw new Error(`Invalid member name for EncryptedData class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Compare values with default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
* @param {*} memberValue Value to compare with default value
|
||||
*/
|
||||
static compareWithDefault(memberName, memberValue)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "version":
|
||||
return (memberValue === 0);
|
||||
case "encryptedContentInfo":
|
||||
return ((EncryptedContentInfo.compareWithDefault("contentType", memberValue.contentType)) &&
|
||||
(EncryptedContentInfo.compareWithDefault("contentEncryptionAlgorithm", memberValue.contentEncryptionAlgorithm)) &&
|
||||
(EncryptedContentInfo.compareWithDefault("encryptedContent", memberValue.encryptedContent)));
|
||||
case "unprotectedAttrs":
|
||||
return (memberValue.length === 0);
|
||||
default:
|
||||
throw new Error(`Invalid member name for EncryptedData class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* EncryptedData ::= SEQUENCE {
|
||||
* version CMSVersion,
|
||||
* encryptedContentInfo EncryptedContentInfo,
|
||||
* unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [version]
|
||||
* @property {string} [encryptedContentInfo]
|
||||
* @property {string} [unprotectedAttrs]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.Integer({ name: (names.version || "") }),
|
||||
EncryptedContentInfo.schema(names.encryptedContentInfo || {}),
|
||||
new asn1js.Constructed({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 1 // [1]
|
||||
},
|
||||
value: [
|
||||
new asn1js.Repeated({
|
||||
name: (names.unprotectedAttrs || ""),
|
||||
value: Attribute.schema()
|
||||
})
|
||||
]
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"version",
|
||||
"encryptedContentInfo",
|
||||
"unprotectedAttrs"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
EncryptedData.schema({
|
||||
names: {
|
||||
version: "version",
|
||||
encryptedContentInfo: {
|
||||
names: {
|
||||
blockName: "encryptedContentInfo"
|
||||
}
|
||||
},
|
||||
unprotectedAttrs: "unprotectedAttrs"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for EncryptedData");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.version = asn1.result.version.valueBlock.valueDec;
|
||||
this.encryptedContentInfo = new EncryptedContentInfo({ schema: asn1.result.encryptedContentInfo });
|
||||
|
||||
if("unprotectedAttrs" in asn1.result)
|
||||
this.unprotectedAttrs = Array.from(asn1.result.unprotectedAttrs, element => new Attribute({ schema: element }));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Create array for output sequence
|
||||
const outputArray = [];
|
||||
|
||||
outputArray.push(new asn1js.Integer({ value: this.version }));
|
||||
outputArray.push(this.encryptedContentInfo.toSchema());
|
||||
|
||||
if("unprotectedAttrs" in this)
|
||||
{
|
||||
outputArray.push(new asn1js.Constructed({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 1 // [1]
|
||||
},
|
||||
value: Array.from(this.unprotectedAttrs, element => element.toSchema())
|
||||
}));
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: outputArray
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
const _object = {
|
||||
version: this.version,
|
||||
encryptedContentInfo: this.encryptedContentInfo.toJSON()
|
||||
};
|
||||
|
||||
if("unprotectedAttrs" in this)
|
||||
_object.unprotectedAttrs = Array.from(this.unprotectedAttrs, element => element.toJSON());
|
||||
|
||||
return _object;
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Create a new CMS Encrypted Data content
|
||||
* @param {Object} parameters Parameters neccessary for encryption
|
||||
* @returns {Promise}
|
||||
*/
|
||||
encrypt(parameters)
|
||||
{
|
||||
//region Check for input parameters
|
||||
if((parameters instanceof Object) === false)
|
||||
return Promise.reject("Parameters must have type \"Object\"");
|
||||
//endregion
|
||||
|
||||
//region Get cryptographic engine
|
||||
const engine = getEngine();
|
||||
if(typeof engine === "undefined")
|
||||
return Promise.reject("Unable to initialize cryptographic engine");
|
||||
//endregion
|
||||
|
||||
//region Set "contentType" parameter
|
||||
parameters.contentType = "1.2.840.113549.1.7.1"; // "data"
|
||||
//endregion
|
||||
|
||||
if("encryptEncryptedContentInfo" in engine.subtle)
|
||||
{
|
||||
return engine.subtle.encryptEncryptedContentInfo(parameters).then(result =>
|
||||
{
|
||||
this.encryptedContentInfo = result;
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.reject(`No support for "encryptEncryptedContentInfo" in current crypto engine ${engine.name}`);
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Create a new CMS Encrypted Data content
|
||||
* @param {Object} parameters Parameters neccessary for encryption
|
||||
*/
|
||||
decrypt(parameters)
|
||||
{
|
||||
//region Check for input parameters
|
||||
if((parameters instanceof Object) === false)
|
||||
return Promise.reject("Parameters must have type \"Object\"");
|
||||
//endregion
|
||||
|
||||
//region Get cryptographic engine
|
||||
const engine = getEngine();
|
||||
if(typeof engine === "undefined")
|
||||
return Promise.reject("Unable to initialize cryptographic engine");
|
||||
//endregion
|
||||
|
||||
//region Set "encryptedContentInfo" value
|
||||
parameters.encryptedContentInfo = this.encryptedContentInfo;
|
||||
//endregion
|
||||
|
||||
if("decryptEncryptedContentInfo" in engine.subtle)
|
||||
return engine.subtle.decryptEncryptedContentInfo(parameters);
|
||||
|
||||
return Promise.reject(`No support for "decryptEncryptedContentInfo" in current crypto engine ${engine.name}`);
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
1729
core/third-party/pkijs/EnvelopedData.js
vendored
Normal file
1729
core/third-party/pkijs/EnvelopedData.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
135
core/third-party/pkijs/ExtKeyUsage.js
vendored
Normal file
135
core/third-party/pkijs/ExtKeyUsage.js
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5280
|
||||
*/
|
||||
export default class ExtKeyUsage
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for ExtKeyUsage class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {Array.<string>}
|
||||
* @desc keyPurposes
|
||||
*/
|
||||
this.keyPurposes = getParametersValue(parameters, "keyPurposes", ExtKeyUsage.defaultValues("keyPurposes"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "keyPurposes":
|
||||
return [];
|
||||
default:
|
||||
throw new Error(`Invalid member name for ExtKeyUsage class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* ExtKeyUsage ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
|
||||
*
|
||||
* KeyPurposeId ::= OBJECT IDENTIFIER
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [keyPurposes]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.Repeated({
|
||||
name: (names.keyPurposes || ""),
|
||||
value: new asn1js.ObjectIdentifier()
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"keyPurposes"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
ExtKeyUsage.schema({
|
||||
names: {
|
||||
keyPurposes: "keyPurposes"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for ExtKeyUsage");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.keyPurposes = Array.from(asn1.result.keyPurposes, element => element.valueBlock.toString());
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: Array.from(this.keyPurposes, element => new asn1js.ObjectIdentifier({ value: element }))
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
return {
|
||||
keyPurposes: Array.from(this.keyPurposes)
|
||||
};
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
453
core/third-party/pkijs/Extension.js
vendored
Normal file
453
core/third-party/pkijs/Extension.js
vendored
Normal file
@@ -0,0 +1,453 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import SubjectDirectoryAttributes from "./SubjectDirectoryAttributes.js";
|
||||
import PrivateKeyUsagePeriod from "./PrivateKeyUsagePeriod.js";
|
||||
import AltName from "./AltName.js";
|
||||
import BasicConstraints from "./BasicConstraints.js";
|
||||
import IssuingDistributionPoint from "./IssuingDistributionPoint.js";
|
||||
import GeneralNames from "./GeneralNames.js";
|
||||
import NameConstraints from "./NameConstraints.js";
|
||||
import CRLDistributionPoints from "./CRLDistributionPoints.js";
|
||||
import CertificatePolicies from "./CertificatePolicies.js";
|
||||
import PolicyMappings from "./PolicyMappings.js";
|
||||
import AuthorityKeyIdentifier from "./AuthorityKeyIdentifier.js";
|
||||
import PolicyConstraints from "./PolicyConstraints.js";
|
||||
import ExtKeyUsage from "./ExtKeyUsage.js";
|
||||
import InfoAccess from "./InfoAccess.js";
|
||||
import SignedCertificateTimestampList from "./SignedCertificateTimestampList.js";
|
||||
import CertificateTemplate from "./CertificateTemplate.js";
|
||||
import CAVersion from "./CAVersion.js";
|
||||
import QCStatements from "./QCStatements.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5280
|
||||
*/
|
||||
export default class Extension
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for Extension class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {string}
|
||||
* @desc extnID
|
||||
*/
|
||||
this.extnID = getParametersValue(parameters, "extnID", Extension.defaultValues("extnID"));
|
||||
/**
|
||||
* @type {boolean}
|
||||
* @desc critical
|
||||
*/
|
||||
this.critical = getParametersValue(parameters, "critical", Extension.defaultValues("critical"));
|
||||
/**
|
||||
* @type {OctetString}
|
||||
* @desc extnValue
|
||||
*/
|
||||
if("extnValue" in parameters)
|
||||
this.extnValue = new asn1js.OctetString({ valueHex: parameters.extnValue });
|
||||
else
|
||||
this.extnValue = Extension.defaultValues("extnValue");
|
||||
|
||||
if("parsedValue" in parameters)
|
||||
/**
|
||||
* @type {Object}
|
||||
* @desc parsedValue
|
||||
*/
|
||||
this.parsedValue = getParametersValue(parameters, "parsedValue", Extension.defaultValues("parsedValue"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "extnID":
|
||||
return "";
|
||||
case "critical":
|
||||
return false;
|
||||
case "extnValue":
|
||||
return new asn1js.OctetString();
|
||||
case "parsedValue":
|
||||
return {};
|
||||
default:
|
||||
throw new Error(`Invalid member name for Extension class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* Extension ::= SEQUENCE {
|
||||
* extnID OBJECT IDENTIFIER,
|
||||
* critical BOOLEAN DEFAULT FALSE,
|
||||
* extnValue OCTET STRING
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [extnID]
|
||||
* @property {string} [critical]
|
||||
* @property {string} [extnValue]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.ObjectIdentifier({ name: (names.extnID || "") }),
|
||||
new asn1js.Boolean({
|
||||
name: (names.critical || ""),
|
||||
optional: true
|
||||
}),
|
||||
new asn1js.OctetString({ name: (names.extnValue || "") })
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"extnID",
|
||||
"critical",
|
||||
"extnValue"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
let asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
Extension.schema({
|
||||
names: {
|
||||
extnID: "extnID",
|
||||
critical: "critical",
|
||||
extnValue: "extnValue"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for Extension");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.extnID = asn1.result.extnID.valueBlock.toString();
|
||||
if("critical" in asn1.result)
|
||||
this.critical = asn1.result.critical.valueBlock.value;
|
||||
this.extnValue = asn1.result.extnValue;
|
||||
|
||||
//region Get "parsedValue" for well-known extensions
|
||||
asn1 = asn1js.fromBER(this.extnValue.valueBlock.valueHex);
|
||||
if(asn1.offset === (-1))
|
||||
return;
|
||||
|
||||
switch(this.extnID)
|
||||
{
|
||||
case "2.5.29.9": // SubjectDirectoryAttributes
|
||||
try
|
||||
{
|
||||
this.parsedValue = new SubjectDirectoryAttributes({ schema: asn1.result });
|
||||
}
|
||||
catch(ex)
|
||||
{
|
||||
this.parsedValue = new SubjectDirectoryAttributes();
|
||||
this.parsedValue.parsingError = "Incorrectly formated SubjectDirectoryAttributes";
|
||||
}
|
||||
break;
|
||||
case "2.5.29.14": // SubjectKeyIdentifier
|
||||
this.parsedValue = asn1.result; // Should be just a simple OCTETSTRING
|
||||
break;
|
||||
case "2.5.29.15": // KeyUsage
|
||||
this.parsedValue = asn1.result; // Should be just a simple BITSTRING
|
||||
break;
|
||||
case "2.5.29.16": // PrivateKeyUsagePeriod
|
||||
try
|
||||
{
|
||||
this.parsedValue = new PrivateKeyUsagePeriod({ schema: asn1.result });
|
||||
}
|
||||
catch(ex)
|
||||
{
|
||||
this.parsedValue = new PrivateKeyUsagePeriod();
|
||||
this.parsedValue.parsingError = "Incorrectly formated PrivateKeyUsagePeriod";
|
||||
}
|
||||
break;
|
||||
case "2.5.29.17": // SubjectAltName
|
||||
case "2.5.29.18": // IssuerAltName
|
||||
try
|
||||
{
|
||||
this.parsedValue = new AltName({ schema: asn1.result });
|
||||
}
|
||||
catch(ex)
|
||||
{
|
||||
this.parsedValue = new AltName();
|
||||
this.parsedValue.parsingError = "Incorrectly formated AltName";
|
||||
}
|
||||
break;
|
||||
case "2.5.29.19": // BasicConstraints
|
||||
try
|
||||
{
|
||||
this.parsedValue = new BasicConstraints({ schema: asn1.result });
|
||||
}
|
||||
catch(ex)
|
||||
{
|
||||
this.parsedValue = new BasicConstraints();
|
||||
this.parsedValue.parsingError = "Incorrectly formated BasicConstraints";
|
||||
}
|
||||
break;
|
||||
case "2.5.29.20": // CRLNumber
|
||||
case "2.5.29.27": // BaseCRLNumber (delta CRL indicator)
|
||||
this.parsedValue = asn1.result; // Should be just a simple INTEGER
|
||||
break;
|
||||
case "2.5.29.21": // CRLReason
|
||||
this.parsedValue = asn1.result; // Should be just a simple ENUMERATED
|
||||
break;
|
||||
case "2.5.29.24": // InvalidityDate
|
||||
this.parsedValue = asn1.result; // Should be just a simple GeneralizedTime
|
||||
break;
|
||||
case "2.5.29.28": // IssuingDistributionPoint
|
||||
try
|
||||
{
|
||||
this.parsedValue = new IssuingDistributionPoint({ schema: asn1.result });
|
||||
}
|
||||
catch(ex)
|
||||
{
|
||||
this.parsedValue = new IssuingDistributionPoint();
|
||||
this.parsedValue.parsingError = "Incorrectly formated IssuingDistributionPoint";
|
||||
}
|
||||
break;
|
||||
case "2.5.29.29": // CertificateIssuer
|
||||
try
|
||||
{
|
||||
this.parsedValue = new GeneralNames({ schema: asn1.result }); // Should be just a simple
|
||||
}
|
||||
catch(ex)
|
||||
{
|
||||
this.parsedValue = new GeneralNames();
|
||||
this.parsedValue.parsingError = "Incorrectly formated GeneralNames";
|
||||
}
|
||||
break;
|
||||
case "2.5.29.30": // NameConstraints
|
||||
try
|
||||
{
|
||||
this.parsedValue = new NameConstraints({ schema: asn1.result });
|
||||
}
|
||||
catch(ex)
|
||||
{
|
||||
this.parsedValue = new NameConstraints();
|
||||
this.parsedValue.parsingError = "Incorrectly formated NameConstraints";
|
||||
}
|
||||
break;
|
||||
case "2.5.29.31": // CRLDistributionPoints
|
||||
case "2.5.29.46": // FreshestCRL
|
||||
try
|
||||
{
|
||||
this.parsedValue = new CRLDistributionPoints({ schema: asn1.result });
|
||||
}
|
||||
catch(ex)
|
||||
{
|
||||
this.parsedValue = new CRLDistributionPoints();
|
||||
this.parsedValue.parsingError = "Incorrectly formated CRLDistributionPoints";
|
||||
}
|
||||
break;
|
||||
case "2.5.29.32": // CertificatePolicies
|
||||
case "1.3.6.1.4.1.311.21.10": // szOID_APPLICATION_CERT_POLICIES - Microsoft-specific OID
|
||||
try
|
||||
{
|
||||
this.parsedValue = new CertificatePolicies({ schema: asn1.result });
|
||||
}
|
||||
catch(ex)
|
||||
{
|
||||
this.parsedValue = new CertificatePolicies();
|
||||
this.parsedValue.parsingError = "Incorrectly formated CertificatePolicies";
|
||||
}
|
||||
break;
|
||||
case "2.5.29.33": // PolicyMappings
|
||||
try
|
||||
{
|
||||
this.parsedValue = new PolicyMappings({ schema: asn1.result });
|
||||
}
|
||||
catch(ex)
|
||||
{
|
||||
this.parsedValue = new PolicyMappings();
|
||||
this.parsedValue.parsingError = "Incorrectly formated CertificatePolicies";
|
||||
}
|
||||
break;
|
||||
case "2.5.29.35": // AuthorityKeyIdentifier
|
||||
try
|
||||
{
|
||||
this.parsedValue = new AuthorityKeyIdentifier({ schema: asn1.result });
|
||||
}
|
||||
catch(ex)
|
||||
{
|
||||
this.parsedValue = new AuthorityKeyIdentifier();
|
||||
this.parsedValue.parsingError = "Incorrectly formated AuthorityKeyIdentifier";
|
||||
}
|
||||
break;
|
||||
case "2.5.29.36": // PolicyConstraints
|
||||
try
|
||||
{
|
||||
this.parsedValue = new PolicyConstraints({ schema: asn1.result });
|
||||
}
|
||||
catch(ex)
|
||||
{
|
||||
this.parsedValue = new PolicyConstraints();
|
||||
this.parsedValue.parsingError = "Incorrectly formated PolicyConstraints";
|
||||
}
|
||||
break;
|
||||
case "2.5.29.37": // ExtKeyUsage
|
||||
try
|
||||
{
|
||||
this.parsedValue = new ExtKeyUsage({ schema: asn1.result });
|
||||
}
|
||||
catch(ex)
|
||||
{
|
||||
this.parsedValue = new ExtKeyUsage();
|
||||
this.parsedValue.parsingError = "Incorrectly formated ExtKeyUsage";
|
||||
}
|
||||
break;
|
||||
case "2.5.29.54": // InhibitAnyPolicy
|
||||
this.parsedValue = asn1.result; // Should be just a simple INTEGER
|
||||
break;
|
||||
case "1.3.6.1.5.5.7.1.1": // AuthorityInfoAccess
|
||||
case "1.3.6.1.5.5.7.1.11": // SubjectInfoAccess
|
||||
try
|
||||
{
|
||||
this.parsedValue = new InfoAccess({ schema: asn1.result });
|
||||
}
|
||||
catch(ex)
|
||||
{
|
||||
this.parsedValue = new InfoAccess();
|
||||
this.parsedValue.parsingError = "Incorrectly formated InfoAccess";
|
||||
}
|
||||
break;
|
||||
case "1.3.6.1.4.1.11129.2.4.2": // SignedCertificateTimestampList
|
||||
try
|
||||
{
|
||||
this.parsedValue = new SignedCertificateTimestampList({ schema: asn1.result });
|
||||
}
|
||||
catch(ex)
|
||||
{
|
||||
this.parsedValue = new SignedCertificateTimestampList();
|
||||
this.parsedValue.parsingError = "Incorrectly formated SignedCertificateTimestampList";
|
||||
}
|
||||
break;
|
||||
case "1.3.6.1.4.1.311.20.2": // szOID_ENROLL_CERTTYPE_EXTENSION - Microsoft-specific extension
|
||||
this.parsedValue = asn1.result; // Used to be simple Unicode string
|
||||
break;
|
||||
case "1.3.6.1.4.1.311.21.2": // szOID_CERTSRV_PREVIOUS_CERT_HASH - Microsoft-specific extension
|
||||
this.parsedValue = asn1.result; // Used to be simple OctetString
|
||||
break;
|
||||
case "1.3.6.1.4.1.311.21.7": // szOID_CERTIFICATE_TEMPLATE - Microsoft-specific extension
|
||||
try
|
||||
{
|
||||
this.parsedValue = new CertificateTemplate({ schema: asn1.result });
|
||||
}
|
||||
catch(ex)
|
||||
{
|
||||
this.parsedValue = new CertificateTemplate();
|
||||
this.parsedValue.parsingError = "Incorrectly formated CertificateTemplate";
|
||||
}
|
||||
break;
|
||||
case "1.3.6.1.4.1.311.21.1": // szOID_CERTSRV_CA_VERSION - Microsoft-specific extension
|
||||
try
|
||||
{
|
||||
this.parsedValue = new CAVersion({ schema: asn1.result });
|
||||
}
|
||||
catch(ex)
|
||||
{
|
||||
this.parsedValue = new CAVersion();
|
||||
this.parsedValue.parsingError = "Incorrectly formated CAVersion";
|
||||
}
|
||||
break;
|
||||
case "1.3.6.1.5.5.7.1.3": // QCStatements
|
||||
try
|
||||
{
|
||||
this.parsedValue = new QCStatements({ schema: asn1.result });
|
||||
}
|
||||
catch(ex)
|
||||
{
|
||||
this.parsedValue = new QCStatements();
|
||||
this.parsedValue.parsingError = "Incorrectly formated QCStatements";
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
//endregion
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Create array for output sequence
|
||||
const outputArray = [];
|
||||
|
||||
outputArray.push(new asn1js.ObjectIdentifier({ value: this.extnID }));
|
||||
|
||||
if(this.critical !== Extension.defaultValues("critical"))
|
||||
outputArray.push(new asn1js.Boolean({ value: this.critical }));
|
||||
|
||||
outputArray.push(this.extnValue);
|
||||
//endregion
|
||||
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: outputArray
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
const object = {
|
||||
extnID: this.extnID,
|
||||
extnValue: this.extnValue.toJSON()
|
||||
};
|
||||
|
||||
if(this.critical !== Extension.defaultValues("critical"))
|
||||
object.critical = this.critical;
|
||||
|
||||
if("parsedValue" in this)
|
||||
{
|
||||
if("toJSON" in this.parsedValue)
|
||||
object.parsedValue = this.parsedValue.toJSON();
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
137
core/third-party/pkijs/Extensions.js
vendored
Normal file
137
core/third-party/pkijs/Extensions.js
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import Extension from "./Extension.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5280
|
||||
*/
|
||||
export default class Extensions
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for Extensions class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {Array.<Extension>}
|
||||
* @desc type
|
||||
*/
|
||||
this.extensions = getParametersValue(parameters, "extensions", Extensions.defaultValues("extensions"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "extensions":
|
||||
return [];
|
||||
default:
|
||||
throw new Error(`Invalid member name for Extensions class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @param {boolean} optional Flag that current schema should be optional
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {}, optional = false)
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [extensions]
|
||||
* @property {string} [extension]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
optional,
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.Repeated({
|
||||
name: (names.extensions || ""),
|
||||
value: Extension.schema(names.extension || {})
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"extensions"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
Extensions.schema({
|
||||
names: {
|
||||
extensions: "extensions"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for Extensions");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.extensions = Array.from(asn1.result.extensions, element => new Extension({ schema: element }));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: Array.from(this.extensions, element => element.toSchema())
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
return {
|
||||
extensions: Array.from(this.extensions, element => element.toJSON())
|
||||
};
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
644
core/third-party/pkijs/GeneralName.js
vendored
Normal file
644
core/third-party/pkijs/GeneralName.js
vendored
Normal file
@@ -0,0 +1,644 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import RelativeDistinguishedNames from "./RelativeDistinguishedNames.js";
|
||||
//**************************************************************************************
|
||||
//region Additional asn1js schema elements existing inside GeneralName schema
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Schema for "builtInStandardAttributes" of "ORAddress"
|
||||
* @param {Object} parameters
|
||||
* @property {Object} [names]
|
||||
* @param {boolean} optional
|
||||
* @returns {Sequence}
|
||||
*/
|
||||
function builtInStandardAttributes(parameters = {}, optional = false)
|
||||
{
|
||||
//builtInStandardAttributes ::= Sequence {
|
||||
// country-name CountryName OPTIONAL,
|
||||
// administration-domain-name AdministrationDomainName OPTIONAL,
|
||||
// network-address [0] IMPLICIT NetworkAddress OPTIONAL,
|
||||
// terminal-identifier [1] IMPLICIT TerminalIdentifier OPTIONAL,
|
||||
// private-domain-name [2] PrivateDomainName OPTIONAL,
|
||||
// organization-name [3] IMPLICIT OrganizationName OPTIONAL,
|
||||
// numeric-user-identifier [4] IMPLICIT NumericUserIdentifier OPTIONAL,
|
||||
// personal-name [5] IMPLICIT PersonalName OPTIONAL,
|
||||
// organizational-unit-names [6] IMPLICIT OrganizationalUnitNames OPTIONAL }
|
||||
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [country_name]
|
||||
* @property {string} [administration_domain_name]
|
||||
* @property {string} [network_address]
|
||||
* @property {string} [terminal_identifier]
|
||||
* @property {string} [private_domain_name]
|
||||
* @property {string} [organization_name]
|
||||
* @property {string} [numeric_user_identifier]
|
||||
* @property {string} [personal_name]
|
||||
* @property {string} [organizational_unit_names]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
optional,
|
||||
value: [
|
||||
new asn1js.Constructed({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 2, // APPLICATION-SPECIFIC
|
||||
tagNumber: 1 // [1]
|
||||
},
|
||||
name: (names.country_name || ""),
|
||||
value: [
|
||||
new asn1js.Choice({
|
||||
value: [
|
||||
new asn1js.NumericString(),
|
||||
new asn1js.PrintableString()
|
||||
]
|
||||
})
|
||||
]
|
||||
}),
|
||||
new asn1js.Constructed({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 2, // APPLICATION-SPECIFIC
|
||||
tagNumber: 2 // [2]
|
||||
},
|
||||
name: (names.administration_domain_name || ""),
|
||||
value: [
|
||||
new asn1js.Choice({
|
||||
value: [
|
||||
new asn1js.NumericString(),
|
||||
new asn1js.PrintableString()
|
||||
]
|
||||
})
|
||||
]
|
||||
}),
|
||||
new asn1js.Primitive({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
name: (names.network_address || ""),
|
||||
isHexOnly: true
|
||||
}),
|
||||
new asn1js.Primitive({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 1 // [1]
|
||||
},
|
||||
name: (names.terminal_identifier || ""),
|
||||
isHexOnly: true
|
||||
}),
|
||||
new asn1js.Constructed({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 2 // [2]
|
||||
},
|
||||
name: (names.private_domain_name || ""),
|
||||
value: [
|
||||
new asn1js.Choice({
|
||||
value: [
|
||||
new asn1js.NumericString(),
|
||||
new asn1js.PrintableString()
|
||||
]
|
||||
})
|
||||
]
|
||||
}),
|
||||
new asn1js.Primitive({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 3 // [3]
|
||||
},
|
||||
name: (names.organization_name || ""),
|
||||
isHexOnly: true
|
||||
}),
|
||||
new asn1js.Primitive({
|
||||
optional: true,
|
||||
name: (names.numeric_user_identifier || ""),
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 4 // [4]
|
||||
},
|
||||
isHexOnly: true
|
||||
}),
|
||||
new asn1js.Constructed({
|
||||
optional: true,
|
||||
name: (names.personal_name || ""),
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 5 // [5]
|
||||
},
|
||||
value: [
|
||||
new asn1js.Primitive({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
isHexOnly: true
|
||||
}),
|
||||
new asn1js.Primitive({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 1 // [1]
|
||||
},
|
||||
isHexOnly: true
|
||||
}),
|
||||
new asn1js.Primitive({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 2 // [2]
|
||||
},
|
||||
isHexOnly: true
|
||||
}),
|
||||
new asn1js.Primitive({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 3 // [3]
|
||||
},
|
||||
isHexOnly: true
|
||||
})
|
||||
]
|
||||
}),
|
||||
new asn1js.Constructed({
|
||||
optional: true,
|
||||
name: (names.organizational_unit_names || ""),
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 6 // [6]
|
||||
},
|
||||
value: [
|
||||
new asn1js.Repeated({
|
||||
value: new asn1js.PrintableString()
|
||||
})
|
||||
]
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Schema for "builtInDomainDefinedAttributes" of "ORAddress"
|
||||
* @param {boolean} optional
|
||||
* @returns {Sequence}
|
||||
*/
|
||||
function builtInDomainDefinedAttributes(optional = false)
|
||||
{
|
||||
return (new asn1js.Sequence({
|
||||
optional,
|
||||
value: [
|
||||
new asn1js.PrintableString(),
|
||||
new asn1js.PrintableString()
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Schema for "builtInDomainDefinedAttributes" of "ORAddress"
|
||||
* @param {boolean} optional
|
||||
* @returns {Set}
|
||||
*/
|
||||
function extensionAttributes(optional = false)
|
||||
{
|
||||
return (new asn1js.Set({
|
||||
optional,
|
||||
value: [
|
||||
new asn1js.Primitive({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
isHexOnly: true
|
||||
}),
|
||||
new asn1js.Constructed({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 1 // [1]
|
||||
},
|
||||
value: [new asn1js.Any()]
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**************************************************************************************
|
||||
//endregion
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5280
|
||||
*/
|
||||
export default class GeneralName
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for GeneralName class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
* @property {number} [type] value type - from a tagged value (0 for "otherName", 1 for "rfc822Name" etc.)
|
||||
* @property {Object} [value] asn1js object having GeneralName value (type depends on "type" value)
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {number}
|
||||
* @desc value type - from a tagged value (0 for "otherName", 1 for "rfc822Name" etc.)
|
||||
*/
|
||||
this.type = getParametersValue(parameters, "type", GeneralName.defaultValues("type"));
|
||||
/**
|
||||
* @type {Object}
|
||||
* @desc asn1js object having GeneralName value (type depends on "type" value)
|
||||
*/
|
||||
this.value = getParametersValue(parameters, "value", GeneralName.defaultValues("value"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "type":
|
||||
return 9;
|
||||
case "value":
|
||||
return {};
|
||||
default:
|
||||
throw new Error(`Invalid member name for GeneralName class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Compare values with default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
* @param {*} memberValue Value to compare with default value
|
||||
*/
|
||||
static compareWithDefault(memberName, memberValue)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "type":
|
||||
return (memberValue === GeneralName.defaultValues(memberName));
|
||||
case "value":
|
||||
return (Object.keys(memberValue).length === 0);
|
||||
default:
|
||||
throw new Error(`Invalid member name for GeneralName class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* GeneralName ::= Choice {
|
||||
* otherName [0] OtherName,
|
||||
* rfc822Name [1] IA5String,
|
||||
* dNSName [2] IA5String,
|
||||
* x400Address [3] ORAddress,
|
||||
* directoryName [4] value,
|
||||
* ediPartyName [5] EDIPartyName,
|
||||
* uniformResourceIdentifier [6] IA5String,
|
||||
* iPAddress [7] OCTET STRING,
|
||||
* registeredID [8] OBJECT IDENTIFIER }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {Object} [directoryName]
|
||||
* @property {Object} [builtInStandardAttributes]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Choice({
|
||||
value: [
|
||||
new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.ObjectIdentifier(),
|
||||
new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: [new asn1js.Any()]
|
||||
})
|
||||
]
|
||||
}),
|
||||
new asn1js.Primitive({
|
||||
name: (names.blockName || ""),
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 1 // [1]
|
||||
}
|
||||
}),
|
||||
new asn1js.Primitive({
|
||||
name: (names.blockName || ""),
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 2 // [2]
|
||||
}
|
||||
}),
|
||||
new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 3 // [3]
|
||||
},
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
builtInStandardAttributes((names.builtInStandardAttributes || {}), false),
|
||||
builtInDomainDefinedAttributes(true),
|
||||
extensionAttributes(true)
|
||||
]
|
||||
}),
|
||||
new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 4 // [4]
|
||||
},
|
||||
name: (names.blockName || ""),
|
||||
value: [RelativeDistinguishedNames.schema(names.directoryName || {})]
|
||||
}),
|
||||
new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 5 // [5]
|
||||
},
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.Constructed({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: [
|
||||
new asn1js.Choice({
|
||||
value: [
|
||||
new asn1js.TeletexString(),
|
||||
new asn1js.PrintableString(),
|
||||
new asn1js.UniversalString(),
|
||||
new asn1js.Utf8String(),
|
||||
new asn1js.BmpString()
|
||||
]
|
||||
})
|
||||
]
|
||||
}),
|
||||
new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 1 // [1]
|
||||
},
|
||||
value: [
|
||||
new asn1js.Choice({
|
||||
value: [
|
||||
new asn1js.TeletexString(),
|
||||
new asn1js.PrintableString(),
|
||||
new asn1js.UniversalString(),
|
||||
new asn1js.Utf8String(),
|
||||
new asn1js.BmpString()
|
||||
]
|
||||
})
|
||||
]
|
||||
})
|
||||
]
|
||||
}),
|
||||
new asn1js.Primitive({
|
||||
name: (names.blockName || ""),
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 6 // [6]
|
||||
}
|
||||
}),
|
||||
new asn1js.Primitive({
|
||||
name: (names.blockName || ""),
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 7 // [7]
|
||||
}
|
||||
}),
|
||||
new asn1js.Primitive({
|
||||
name: (names.blockName || ""),
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 8 // [8]
|
||||
}
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"blockName",
|
||||
"otherName",
|
||||
"rfc822Name",
|
||||
"dNSName",
|
||||
"x400Address",
|
||||
"directoryName",
|
||||
"ediPartyName",
|
||||
"uniformResourceIdentifier",
|
||||
"iPAddress",
|
||||
"registeredID"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
GeneralName.schema({
|
||||
names: {
|
||||
blockName: "blockName",
|
||||
otherName: "otherName",
|
||||
rfc822Name: "rfc822Name",
|
||||
dNSName: "dNSName",
|
||||
x400Address: "x400Address",
|
||||
directoryName: {
|
||||
names: {
|
||||
blockName: "directoryName"
|
||||
}
|
||||
},
|
||||
ediPartyName: "ediPartyName",
|
||||
uniformResourceIdentifier: "uniformResourceIdentifier",
|
||||
iPAddress: "iPAddress",
|
||||
registeredID: "registeredID"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for GeneralName");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.type = asn1.result.blockName.idBlock.tagNumber;
|
||||
|
||||
switch(this.type)
|
||||
{
|
||||
case 0: // otherName
|
||||
this.value = asn1.result.blockName;
|
||||
break;
|
||||
case 1: // rfc822Name + dNSName + uniformResourceIdentifier
|
||||
case 2:
|
||||
case 6:
|
||||
{
|
||||
const value = asn1.result.blockName;
|
||||
|
||||
value.idBlock.tagClass = 1; // UNIVERSAL
|
||||
value.idBlock.tagNumber = 22; // IA5STRING
|
||||
|
||||
const valueBER = value.toBER(false);
|
||||
|
||||
this.value = asn1js.fromBER(valueBER).result.valueBlock.value;
|
||||
}
|
||||
break;
|
||||
case 3: // x400Address
|
||||
this.value = asn1.result.blockName;
|
||||
break;
|
||||
case 4: // directoryName
|
||||
this.value = new RelativeDistinguishedNames({ schema: asn1.result.directoryName });
|
||||
break;
|
||||
case 5: // ediPartyName
|
||||
this.value = asn1.result.ediPartyName;
|
||||
break;
|
||||
case 7: // iPAddress
|
||||
this.value = new asn1js.OctetString({ valueHex: asn1.result.blockName.valueBlock.valueHex });
|
||||
break;
|
||||
case 8: // registeredID
|
||||
{
|
||||
const value = asn1.result.blockName;
|
||||
|
||||
value.idBlock.tagClass = 1; // UNIVERSAL
|
||||
value.idBlock.tagNumber = 6; // ObjectIdentifier
|
||||
|
||||
const valueBER = value.toBER(false);
|
||||
|
||||
this.value = asn1js.fromBER(valueBER).result.valueBlock.toString(); // Getting a string representation of the ObjectIdentifier
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
switch(this.type)
|
||||
{
|
||||
case 0:
|
||||
case 3:
|
||||
case 5:
|
||||
return new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: this.type
|
||||
},
|
||||
value: [
|
||||
this.value
|
||||
]
|
||||
});
|
||||
case 1:
|
||||
case 2:
|
||||
case 6:
|
||||
{
|
||||
const value = new asn1js.IA5String({ value: this.value });
|
||||
|
||||
value.idBlock.tagClass = 3;
|
||||
value.idBlock.tagNumber = this.type;
|
||||
|
||||
return value;
|
||||
}
|
||||
case 4:
|
||||
return new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 4
|
||||
},
|
||||
value: [this.value.toSchema()]
|
||||
});
|
||||
case 7:
|
||||
{
|
||||
const value = this.value;
|
||||
|
||||
value.idBlock.tagClass = 3;
|
||||
value.idBlock.tagNumber = this.type;
|
||||
|
||||
return value;
|
||||
}
|
||||
case 8:
|
||||
{
|
||||
const value = new asn1js.ObjectIdentifier({ value: this.value });
|
||||
|
||||
value.idBlock.tagClass = 3;
|
||||
value.idBlock.tagNumber = this.type;
|
||||
|
||||
return value;
|
||||
}
|
||||
default:
|
||||
return GeneralName.schema();
|
||||
}
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
const _object = {
|
||||
type: this.type,
|
||||
value: ""
|
||||
};
|
||||
|
||||
if((typeof this.value) === "string")
|
||||
_object.value = this.value;
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
_object.value = this.value.toJSON();
|
||||
}
|
||||
catch(ex){}
|
||||
}
|
||||
|
||||
return _object;
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
138
core/third-party/pkijs/GeneralNames.js
vendored
Normal file
138
core/third-party/pkijs/GeneralNames.js
vendored
Normal file
@@ -0,0 +1,138 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import GeneralName from "./GeneralName.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5280
|
||||
*/
|
||||
export default class GeneralNames
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for GeneralNames class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {Array.<GeneralName>}
|
||||
* @desc Array of "general names"
|
||||
*/
|
||||
this.names = getParametersValue(parameters, "names", GeneralNames.defaultValues("names"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "names":
|
||||
return [];
|
||||
default:
|
||||
throw new Error(`Invalid member name for GeneralNames class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @param {boolean} [optional=false] Flag would be element optional or not
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {}, optional = false)
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} utcTimeName Name for "utcTimeName" choice
|
||||
* @property {string} generalTimeName Name for "generalTimeName" choice
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
optional,
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.Repeated({
|
||||
name: (names.generalNames || ""),
|
||||
value: GeneralName.schema()
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"names",
|
||||
"generalNames"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
GeneralNames.schema({
|
||||
names: {
|
||||
blockName: "names",
|
||||
generalNames: "generalNames"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for GeneralNames");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.names = Array.from(asn1.result.generalNames, element => new GeneralName({ schema: element }));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: Array.from(this.names, element => element.toSchema())
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
return {
|
||||
names: Array.from(this.names, element => element.toJSON())
|
||||
};
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
257
core/third-party/pkijs/GeneralSubtree.js
vendored
Normal file
257
core/third-party/pkijs/GeneralSubtree.js
vendored
Normal file
@@ -0,0 +1,257 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import GeneralName from "./GeneralName.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5280
|
||||
*/
|
||||
export default class GeneralSubtree
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for GeneralSubtree class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {GeneralName}
|
||||
* @desc base
|
||||
*/
|
||||
this.base = getParametersValue(parameters, "base", GeneralSubtree.defaultValues("base"));
|
||||
|
||||
/**
|
||||
* @type {number|Integer}
|
||||
* @desc base
|
||||
*/
|
||||
this.minimum = getParametersValue(parameters, "minimum", GeneralSubtree.defaultValues("minimum"));
|
||||
|
||||
if("maximum" in parameters)
|
||||
/**
|
||||
* @type {number|Integer}
|
||||
* @desc minimum
|
||||
*/
|
||||
this.maximum = getParametersValue(parameters, "maximum", GeneralSubtree.defaultValues("maximum"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "base":
|
||||
return new GeneralName();
|
||||
case "minimum":
|
||||
return 0;
|
||||
case "maximum":
|
||||
return 0;
|
||||
default:
|
||||
throw new Error(`Invalid member name for GeneralSubtree class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* GeneralSubtree ::= SEQUENCE {
|
||||
* base GeneralName,
|
||||
* minimum [0] BaseDistance DEFAULT 0,
|
||||
* maximum [1] BaseDistance OPTIONAL }
|
||||
*
|
||||
* BaseDistance ::= INTEGER (0..MAX)
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [base]
|
||||
* @property {string} [minimum]
|
||||
* @property {string} [maximum]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
GeneralName.schema(names.base || {}),
|
||||
new asn1js.Constructed({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: [new asn1js.Integer({ name: (names.minimum || "") })]
|
||||
}),
|
||||
new asn1js.Constructed({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 1 // [1]
|
||||
},
|
||||
value: [new asn1js.Integer({ name: (names.maximum || "") })]
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"base",
|
||||
"minimum",
|
||||
"maximum"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
GeneralSubtree.schema({
|
||||
names: {
|
||||
base: {
|
||||
names: {
|
||||
blockName: "base"
|
||||
}
|
||||
},
|
||||
minimum: "minimum",
|
||||
maximum: "maximum"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for GeneralSubtree");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.base = new GeneralName({ schema: asn1.result.base });
|
||||
|
||||
if("minimum" in asn1.result)
|
||||
{
|
||||
if(asn1.result.minimum.valueBlock.isHexOnly)
|
||||
this.minimum = asn1.result.minimum;
|
||||
else
|
||||
this.minimum = asn1.result.minimum.valueBlock.valueDec;
|
||||
}
|
||||
|
||||
if("maximum" in asn1.result)
|
||||
{
|
||||
if(asn1.result.maximum.valueBlock.isHexOnly)
|
||||
this.maximum = asn1.result.maximum;
|
||||
else
|
||||
this.maximum = asn1.result.maximum.valueBlock.valueDec;
|
||||
}
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Create array for output sequence
|
||||
const outputArray = [];
|
||||
|
||||
outputArray.push(this.base.toSchema());
|
||||
|
||||
if(this.minimum !== 0)
|
||||
{
|
||||
let valueMinimum = 0;
|
||||
|
||||
if(this.minimum instanceof asn1js.Integer)
|
||||
valueMinimum = this.minimum;
|
||||
else
|
||||
valueMinimum = new asn1js.Integer({ value: this.minimum });
|
||||
|
||||
outputArray.push(new asn1js.Constructed({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: [valueMinimum]
|
||||
}));
|
||||
}
|
||||
|
||||
if("maximum" in this)
|
||||
{
|
||||
let valueMaximum = 0;
|
||||
|
||||
if(this.maximum instanceof asn1js.Integer)
|
||||
valueMaximum = this.maximum;
|
||||
else
|
||||
valueMaximum = new asn1js.Integer({ value: this.maximum });
|
||||
|
||||
outputArray.push(new asn1js.Constructed({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 1 // [1]
|
||||
},
|
||||
value: [valueMaximum]
|
||||
}));
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: outputArray
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
const object = {
|
||||
base: this.base.toJSON()
|
||||
};
|
||||
|
||||
if(this.minimum !== 0)
|
||||
{
|
||||
if((typeof this.minimum) === "number")
|
||||
object.minimum = this.minimum;
|
||||
else
|
||||
object.minimum = this.minimum.toJSON();
|
||||
}
|
||||
|
||||
if("maximum" in this)
|
||||
{
|
||||
if((typeof this.maximum) === "number")
|
||||
object.maximum = this.maximum;
|
||||
else
|
||||
object.maximum = this.maximum.toJSON();
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
135
core/third-party/pkijs/InfoAccess.js
vendored
Normal file
135
core/third-party/pkijs/InfoAccess.js
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import AccessDescription from "./AccessDescription.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5280
|
||||
*/
|
||||
export default class InfoAccess
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for InfoAccess class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {Array.<AccessDescription>}
|
||||
* @desc accessDescriptions
|
||||
*/
|
||||
this.accessDescriptions = getParametersValue(parameters, "accessDescriptions", InfoAccess.defaultValues("accessDescriptions"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "accessDescriptions":
|
||||
return [];
|
||||
default:
|
||||
throw new Error(`Invalid member name for InfoAccess class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* AuthorityInfoAccessSyntax ::=
|
||||
* SEQUENCE SIZE (1..MAX) OF AccessDescription
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [accessDescriptions]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.Repeated({
|
||||
name: (names.accessDescriptions || ""),
|
||||
value: AccessDescription.schema()
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"accessDescriptions"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
InfoAccess.schema({
|
||||
names: {
|
||||
accessDescriptions: "accessDescriptions"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for InfoAccess");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.accessDescriptions = Array.from(asn1.result.accessDescriptions, element => new AccessDescription({ schema: element }));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: Array.from(this.accessDescriptions, element => element.toSchema())
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
return {
|
||||
accessDescriptions: Array.from(this.accessDescriptions, element => element.toJSON())
|
||||
};
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
155
core/third-party/pkijs/IssuerAndSerialNumber.js
vendored
Normal file
155
core/third-party/pkijs/IssuerAndSerialNumber.js
vendored
Normal file
@@ -0,0 +1,155 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import RelativeDistinguishedNames from "./RelativeDistinguishedNames.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5652
|
||||
*/
|
||||
export default class IssuerAndSerialNumber
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for IssuerAndSerialNumber class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {RelativeDistinguishedNames}
|
||||
* @desc issuer
|
||||
*/
|
||||
this.issuer = getParametersValue(parameters, "issuer", IssuerAndSerialNumber.defaultValues("issuer"));
|
||||
/**
|
||||
* @type {Integer}
|
||||
* @desc serialNumber
|
||||
*/
|
||||
this.serialNumber = getParametersValue(parameters, "serialNumber", IssuerAndSerialNumber.defaultValues("serialNumber"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "issuer":
|
||||
return new RelativeDistinguishedNames();
|
||||
case "serialNumber":
|
||||
return new asn1js.Integer();
|
||||
default:
|
||||
throw new Error(`Invalid member name for IssuerAndSerialNumber class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* IssuerAndSerialNumber ::= SEQUENCE {
|
||||
* issuer Name,
|
||||
* serialNumber CertificateSerialNumber }
|
||||
*
|
||||
* CertificateSerialNumber ::= INTEGER
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [issuer]
|
||||
* @property {string} [serialNumber]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
RelativeDistinguishedNames.schema(names.issuer || {}),
|
||||
new asn1js.Integer({ name: (names.serialNumber || "") })
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"issuer",
|
||||
"serialNumber"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
IssuerAndSerialNumber.schema({
|
||||
names: {
|
||||
issuer: {
|
||||
names: {
|
||||
blockName: "issuer"
|
||||
}
|
||||
},
|
||||
serialNumber: "serialNumber"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for IssuerAndSerialNumber");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.issuer = new RelativeDistinguishedNames({ schema: asn1.result.issuer });
|
||||
this.serialNumber = asn1.result.serialNumber;
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: [
|
||||
this.issuer.toSchema(),
|
||||
this.serialNumber
|
||||
]
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
return {
|
||||
issuer: this.issuer.toJSON(),
|
||||
serialNumber: this.serialNumber.toJSON()
|
||||
};
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
449
core/third-party/pkijs/IssuingDistributionPoint.js
vendored
Normal file
449
core/third-party/pkijs/IssuingDistributionPoint.js
vendored
Normal file
@@ -0,0 +1,449 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import GeneralName from "./GeneralName.js";
|
||||
import RelativeDistinguishedNames from "./RelativeDistinguishedNames.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5280
|
||||
*/
|
||||
export default class IssuingDistributionPoint
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for IssuingDistributionPoint class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
if("distributionPoint" in parameters)
|
||||
/**
|
||||
* @type {Array.<GeneralName>|RelativeDistinguishedNames}
|
||||
* @desc distributionPoint
|
||||
*/
|
||||
this.distributionPoint = getParametersValue(parameters, "distributionPoint", IssuingDistributionPoint.defaultValues("distributionPoint"));
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
* @desc onlyContainsUserCerts
|
||||
*/
|
||||
this.onlyContainsUserCerts = getParametersValue(parameters, "onlyContainsUserCerts", IssuingDistributionPoint.defaultValues("onlyContainsUserCerts"));
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
* @desc onlyContainsCACerts
|
||||
*/
|
||||
this.onlyContainsCACerts = getParametersValue(parameters, "onlyContainsCACerts", IssuingDistributionPoint.defaultValues("onlyContainsCACerts"));
|
||||
|
||||
if("onlySomeReasons" in parameters)
|
||||
/**
|
||||
* @type {number}
|
||||
* @desc onlySomeReasons
|
||||
*/
|
||||
this.onlySomeReasons = getParametersValue(parameters, "onlySomeReasons", IssuingDistributionPoint.defaultValues("onlySomeReasons"));
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
* @desc indirectCRL
|
||||
*/
|
||||
this.indirectCRL = getParametersValue(parameters, "indirectCRL", IssuingDistributionPoint.defaultValues("indirectCRL"));
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
* @desc onlyContainsAttributeCerts
|
||||
*/
|
||||
this.onlyContainsAttributeCerts = getParametersValue(parameters, "onlyContainsAttributeCerts", IssuingDistributionPoint.defaultValues("onlyContainsAttributeCerts"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "distributionPoint":
|
||||
return [];
|
||||
case "onlyContainsUserCerts":
|
||||
return false;
|
||||
case "onlyContainsCACerts":
|
||||
return false;
|
||||
case "onlySomeReasons":
|
||||
return 0;
|
||||
case "indirectCRL":
|
||||
return false;
|
||||
case "onlyContainsAttributeCerts":
|
||||
return false;
|
||||
default:
|
||||
throw new Error(`Invalid member name for IssuingDistributionPoint class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* IssuingDistributionPoint ::= SEQUENCE {
|
||||
* distributionPoint [0] DistributionPointName OPTIONAL,
|
||||
* onlyContainsUserCerts [1] BOOLEAN DEFAULT FALSE,
|
||||
* onlyContainsCACerts [2] BOOLEAN DEFAULT FALSE,
|
||||
* onlySomeReasons [3] ReasonFlags OPTIONAL,
|
||||
* indirectCRL [4] BOOLEAN DEFAULT FALSE,
|
||||
* onlyContainsAttributeCerts [5] BOOLEAN DEFAULT FALSE }
|
||||
*
|
||||
* ReasonFlags ::= BIT STRING {
|
||||
* unused (0),
|
||||
* keyCompromise (1),
|
||||
* cACompromise (2),
|
||||
* affiliationChanged (3),
|
||||
* superseded (4),
|
||||
* cessationOfOperation (5),
|
||||
* certificateHold (6),
|
||||
* privilegeWithdrawn (7),
|
||||
* aACompromise (8) }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [distributionPoint]
|
||||
* @property {string} [distributionPointNames]
|
||||
* @property {string} [onlyContainsUserCerts]
|
||||
* @property {string} [onlyContainsCACerts]
|
||||
* @property {string} [onlySomeReasons]
|
||||
* @property {string} [indirectCRL]
|
||||
* @property {string} [onlyContainsAttributeCerts]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.Constructed({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: [
|
||||
new asn1js.Choice({
|
||||
value: [
|
||||
new asn1js.Constructed({
|
||||
name: (names.distributionPoint || ""),
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: [
|
||||
new asn1js.Repeated({
|
||||
name: (names.distributionPointNames || ""),
|
||||
value: GeneralName.schema()
|
||||
})
|
||||
]
|
||||
}),
|
||||
new asn1js.Constructed({
|
||||
name: (names.distributionPoint || ""),
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 1 // [1]
|
||||
},
|
||||
value: RelativeDistinguishedNames.schema().valueBlock.value
|
||||
})
|
||||
]
|
||||
})
|
||||
]
|
||||
}),
|
||||
new asn1js.Primitive({
|
||||
name: (names.onlyContainsUserCerts || ""),
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 1 // [1]
|
||||
}
|
||||
}), // IMPLICIT boolean value
|
||||
new asn1js.Primitive({
|
||||
name: (names.onlyContainsCACerts || ""),
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 2 // [2]
|
||||
}
|
||||
}), // IMPLICIT boolean value
|
||||
new asn1js.Primitive({
|
||||
name: (names.onlySomeReasons || ""),
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 3 // [3]
|
||||
}
|
||||
}), // IMPLICIT bitstring value
|
||||
new asn1js.Primitive({
|
||||
name: (names.indirectCRL || ""),
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 4 // [4]
|
||||
}
|
||||
}), // IMPLICIT boolean value
|
||||
new asn1js.Primitive({
|
||||
name: (names.onlyContainsAttributeCerts || ""),
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 5 // [5]
|
||||
}
|
||||
}) // IMPLICIT boolean value
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"distributionPoint",
|
||||
"distributionPointNames",
|
||||
"onlyContainsUserCerts",
|
||||
"onlyContainsCACerts",
|
||||
"onlySomeReasons",
|
||||
"indirectCRL",
|
||||
"onlyContainsAttributeCerts"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
IssuingDistributionPoint.schema({
|
||||
names: {
|
||||
distributionPoint: "distributionPoint",
|
||||
distributionPointNames: "distributionPointNames",
|
||||
onlyContainsUserCerts: "onlyContainsUserCerts",
|
||||
onlyContainsCACerts: "onlyContainsCACerts",
|
||||
onlySomeReasons: "onlySomeReasons",
|
||||
indirectCRL: "indirectCRL",
|
||||
onlyContainsAttributeCerts: "onlyContainsAttributeCerts"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for IssuingDistributionPoint");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
if("distributionPoint" in asn1.result)
|
||||
{
|
||||
switch(true)
|
||||
{
|
||||
case (asn1.result.distributionPoint.idBlock.tagNumber === 0): // GENERAL_NAMES variant
|
||||
this.distributionPoint = Array.from(asn1.result.distributionPointNames, element => new GeneralName({ schema: element }));
|
||||
break;
|
||||
case (asn1.result.distributionPoint.idBlock.tagNumber === 1): // RDN variant
|
||||
{
|
||||
this.distributionPoint = new RelativeDistinguishedNames({
|
||||
schema: new asn1js.Sequence({
|
||||
value: asn1.result.distributionPoint.valueBlock.value
|
||||
})
|
||||
});
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new Error("Unknown tagNumber for distributionPoint: {$asn1.result.distributionPoint.idBlock.tagNumber}");
|
||||
}
|
||||
}
|
||||
|
||||
if("onlyContainsUserCerts" in asn1.result)
|
||||
{
|
||||
const view = new Uint8Array(asn1.result.onlyContainsUserCerts.valueBlock.valueHex);
|
||||
this.onlyContainsUserCerts = (view[0] !== 0x00);
|
||||
}
|
||||
|
||||
if("onlyContainsCACerts" in asn1.result)
|
||||
{
|
||||
const view = new Uint8Array(asn1.result.onlyContainsCACerts.valueBlock.valueHex);
|
||||
this.onlyContainsCACerts = (view[0] !== 0x00);
|
||||
}
|
||||
|
||||
if("onlySomeReasons" in asn1.result)
|
||||
{
|
||||
const view = new Uint8Array(asn1.result.onlySomeReasons.valueBlock.valueHex);
|
||||
this.onlySomeReasons = view[0];
|
||||
}
|
||||
|
||||
if("indirectCRL" in asn1.result)
|
||||
{
|
||||
const view = new Uint8Array(asn1.result.indirectCRL.valueBlock.valueHex);
|
||||
this.indirectCRL = (view[0] !== 0x00);
|
||||
}
|
||||
|
||||
if("onlyContainsAttributeCerts" in asn1.result)
|
||||
{
|
||||
const view = new Uint8Array(asn1.result.onlyContainsAttributeCerts.valueBlock.valueHex);
|
||||
this.onlyContainsAttributeCerts = (view[0] !== 0x00);
|
||||
}
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Create array for output sequence
|
||||
const outputArray = [];
|
||||
|
||||
if("distributionPoint" in this)
|
||||
{
|
||||
let value;
|
||||
|
||||
if(this.distributionPoint instanceof Array)
|
||||
{
|
||||
value = new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: Array.from(this.distributionPoint, element => element.toSchema())
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
value = this.distributionPoint.toSchema();
|
||||
|
||||
value.idBlock.tagClass = 3; // CONTEXT - SPECIFIC
|
||||
value.idBlock.tagNumber = 1; // [1]
|
||||
}
|
||||
|
||||
outputArray.push(new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: [value]
|
||||
}));
|
||||
}
|
||||
|
||||
if(this.onlyContainsUserCerts !== IssuingDistributionPoint.defaultValues("onlyContainsUserCerts"))
|
||||
{
|
||||
outputArray.push(new asn1js.Primitive({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 1 // [1]
|
||||
},
|
||||
valueHex: (new Uint8Array([0xFF])).buffer
|
||||
}));
|
||||
}
|
||||
|
||||
if(this.onlyContainsCACerts !== IssuingDistributionPoint.defaultValues("onlyContainsCACerts"))
|
||||
{
|
||||
outputArray.push(new asn1js.Primitive({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 2 // [2]
|
||||
},
|
||||
valueHex: (new Uint8Array([0xFF])).buffer
|
||||
}));
|
||||
}
|
||||
|
||||
if("onlySomeReasons" in this)
|
||||
{
|
||||
const buffer = new ArrayBuffer(1);
|
||||
const view = new Uint8Array(buffer);
|
||||
|
||||
view[0] = this.onlySomeReasons;
|
||||
|
||||
outputArray.push(new asn1js.Primitive({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 3 // [3]
|
||||
},
|
||||
valueHex: buffer
|
||||
}));
|
||||
}
|
||||
|
||||
if(this.indirectCRL !== IssuingDistributionPoint.defaultValues("indirectCRL"))
|
||||
{
|
||||
outputArray.push(new asn1js.Primitive({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 4 // [4]
|
||||
},
|
||||
valueHex: (new Uint8Array([0xFF])).buffer
|
||||
}));
|
||||
}
|
||||
|
||||
if(this.onlyContainsAttributeCerts !== IssuingDistributionPoint.defaultValues("onlyContainsAttributeCerts"))
|
||||
{
|
||||
outputArray.push(new asn1js.Primitive({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 5 // [5]
|
||||
},
|
||||
valueHex: (new Uint8Array([0xFF])).buffer
|
||||
}));
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: outputArray
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
const object = {};
|
||||
|
||||
if("distributionPoint" in this)
|
||||
{
|
||||
if(this.distributionPoint instanceof Array)
|
||||
object.distributionPoint = Array.from(this.distributionPoint, element => element.toJSON());
|
||||
else
|
||||
object.distributionPoint = this.distributionPoint.toJSON();
|
||||
}
|
||||
|
||||
if(this.onlyContainsUserCerts !== IssuingDistributionPoint.defaultValues("onlyContainsUserCerts"))
|
||||
object.onlyContainsUserCerts = this.onlyContainsUserCerts;
|
||||
|
||||
if(this.onlyContainsCACerts !== IssuingDistributionPoint.defaultValues("onlyContainsCACerts"))
|
||||
object.onlyContainsCACerts = this.onlyContainsCACerts;
|
||||
|
||||
if("onlySomeReasons" in this)
|
||||
object.onlySomeReasons = this.onlySomeReasons;
|
||||
|
||||
if(this.indirectCRL !== IssuingDistributionPoint.defaultValues("indirectCRL"))
|
||||
object.indirectCRL = this.indirectCRL;
|
||||
|
||||
if(this.onlyContainsAttributeCerts !== IssuingDistributionPoint.defaultValues("onlyContainsAttributeCerts"))
|
||||
object.onlyContainsAttributeCerts = this.onlyContainsAttributeCerts;
|
||||
|
||||
return object;
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
220
core/third-party/pkijs/KEKIdentifier.js
vendored
Normal file
220
core/third-party/pkijs/KEKIdentifier.js
vendored
Normal file
@@ -0,0 +1,220 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import OtherKeyAttribute from "./OtherKeyAttribute.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5652
|
||||
*/
|
||||
export default class KEKIdentifier
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for KEKIdentifier class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {OctetString}
|
||||
* @desc keyIdentifier
|
||||
*/
|
||||
this.keyIdentifier = getParametersValue(parameters, "keyIdentifier", KEKIdentifier.defaultValues("keyIdentifier"));
|
||||
|
||||
if("date" in parameters)
|
||||
/**
|
||||
* @type {GeneralizedTime}
|
||||
* @desc date
|
||||
*/
|
||||
this.date = getParametersValue(parameters, "date", KEKIdentifier.defaultValues("date"));
|
||||
if("other" in parameters)
|
||||
/**
|
||||
* @type {OtherKeyAttribute}
|
||||
* @desc other
|
||||
*/
|
||||
this.other = getParametersValue(parameters, "other", KEKIdentifier.defaultValues("other"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "keyIdentifier":
|
||||
return new asn1js.OctetString();
|
||||
case "date":
|
||||
return new asn1js.GeneralizedTime();
|
||||
case "other":
|
||||
return new OtherKeyAttribute();
|
||||
default:
|
||||
throw new Error(`Invalid member name for KEKIdentifier class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Compare values with default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
* @param {*} memberValue Value to compare with default value
|
||||
*/
|
||||
static compareWithDefault(memberName, memberValue)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "keyIdentifier":
|
||||
return (memberValue.isEqual(KEKIdentifier.defaultValues("keyIdentifier")));
|
||||
case "date":
|
||||
// noinspection OverlyComplexBooleanExpressionJS
|
||||
return ((memberValue.year === 0) &&
|
||||
(memberValue.month === 0) &&
|
||||
(memberValue.day === 0) &&
|
||||
(memberValue.hour === 0) &&
|
||||
(memberValue.minute === 0) &&
|
||||
(memberValue.second === 0) &&
|
||||
(memberValue.millisecond === 0));
|
||||
case "other":
|
||||
return ((memberValue.compareWithDefault("keyAttrId", memberValue.keyAttrId)) &&
|
||||
(("keyAttr" in memberValue) === false));
|
||||
default:
|
||||
throw new Error(`Invalid member name for KEKIdentifier class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* KEKIdentifier ::= SEQUENCE {
|
||||
* keyIdentifier OCTET STRING,
|
||||
* date GeneralizedTime OPTIONAL,
|
||||
* other OtherKeyAttribute OPTIONAL }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [keyIdentifier]
|
||||
* @property {string} [date]
|
||||
* @property {string} [other]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.OctetString({ name: (names.keyIdentifier || "") }),
|
||||
new asn1js.GeneralizedTime({
|
||||
optional: true,
|
||||
name: (names.date || "")
|
||||
}),
|
||||
OtherKeyAttribute.schema(names.other || {})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"keyIdentifier",
|
||||
"date",
|
||||
"other"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
KEKIdentifier.schema({
|
||||
names: {
|
||||
keyIdentifier: "keyIdentifier",
|
||||
date: "date",
|
||||
other: {
|
||||
names: {
|
||||
blockName: "other"
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for KEKIdentifier");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.keyIdentifier = asn1.result.keyIdentifier;
|
||||
|
||||
if("date" in asn1.result)
|
||||
this.date = asn1.result.date;
|
||||
|
||||
if("other" in asn1.result)
|
||||
this.other = new OtherKeyAttribute({ schema: asn1.result.other });
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Create array for output sequence
|
||||
const outputArray = [];
|
||||
|
||||
outputArray.push(this.keyIdentifier);
|
||||
|
||||
if("date" in this)
|
||||
outputArray.push(this.date);
|
||||
|
||||
if("other" in this)
|
||||
outputArray.push(this.other.toSchema());
|
||||
//endregion
|
||||
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: outputArray
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
const _object = {
|
||||
keyIdentifier: this.keyIdentifier.toJSON()
|
||||
};
|
||||
|
||||
if("date" in this)
|
||||
_object.date = this.date;
|
||||
|
||||
if("other" in this)
|
||||
_object.other = this.other.toJSON();
|
||||
|
||||
return _object;
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
221
core/third-party/pkijs/KEKRecipientInfo.js
vendored
Normal file
221
core/third-party/pkijs/KEKRecipientInfo.js
vendored
Normal file
@@ -0,0 +1,221 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import KEKIdentifier from "./KEKIdentifier.js";
|
||||
import AlgorithmIdentifier from "./AlgorithmIdentifier.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5652
|
||||
*/
|
||||
export default class KEKRecipientInfo
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for KEKRecipientInfo class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {number}
|
||||
* @desc version
|
||||
*/
|
||||
this.version = getParametersValue(parameters, "version", KEKRecipientInfo.defaultValues("version"));
|
||||
/**
|
||||
* @type {KEKIdentifier}
|
||||
* @desc kekid
|
||||
*/
|
||||
this.kekid = getParametersValue(parameters, "kekid", KEKRecipientInfo.defaultValues("kekid"));
|
||||
/**
|
||||
* @type {AlgorithmIdentifier}
|
||||
* @desc keyEncryptionAlgorithm
|
||||
*/
|
||||
this.keyEncryptionAlgorithm = getParametersValue(parameters, "keyEncryptionAlgorithm", KEKRecipientInfo.defaultValues("keyEncryptionAlgorithm"));
|
||||
/**
|
||||
* @type {OctetString}
|
||||
* @desc encryptedKey
|
||||
*/
|
||||
this.encryptedKey = getParametersValue(parameters, "encryptedKey", KEKRecipientInfo.defaultValues("encryptedKey"));
|
||||
/**
|
||||
* @type {ArrayBuffer}
|
||||
* @desc preDefinedKEK KEK using to encrypt CEK
|
||||
*/
|
||||
this.preDefinedKEK = getParametersValue(parameters, "preDefinedKEK", KEKRecipientInfo.defaultValues("preDefinedKEK"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "version":
|
||||
return 0;
|
||||
case "kekid":
|
||||
return new KEKIdentifier();
|
||||
case "keyEncryptionAlgorithm":
|
||||
return new AlgorithmIdentifier();
|
||||
case "encryptedKey":
|
||||
return new asn1js.OctetString();
|
||||
case "preDefinedKEK":
|
||||
return new ArrayBuffer(0);
|
||||
default:
|
||||
throw new Error(`Invalid member name for KEKRecipientInfo class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Compare values with default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
* @param {*} memberValue Value to compare with default value
|
||||
*/
|
||||
static compareWithDefault(memberName, memberValue)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "KEKRecipientInfo":
|
||||
return (memberValue === KEKRecipientInfo.defaultValues("version"));
|
||||
case "kekid":
|
||||
return ((memberValue.compareWithDefault("keyIdentifier", memberValue.keyIdentifier)) &&
|
||||
(("date" in memberValue) === false) &&
|
||||
(("other" in memberValue) === false));
|
||||
case "keyEncryptionAlgorithm":
|
||||
return ((memberValue.algorithmId === "") && (("algorithmParams" in memberValue) === false));
|
||||
case "encryptedKey":
|
||||
return (memberValue.isEqual(KEKRecipientInfo.defaultValues("encryptedKey")));
|
||||
case "preDefinedKEK":
|
||||
return (memberValue.byteLength === 0);
|
||||
default:
|
||||
throw new Error(`Invalid member name for KEKRecipientInfo class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* KEKRecipientInfo ::= SEQUENCE {
|
||||
* version CMSVersion, -- always set to 4
|
||||
* kekid KEKIdentifier,
|
||||
* keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
|
||||
* encryptedKey EncryptedKey }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [version]
|
||||
* @property {string} [kekid]
|
||||
* @property {string} [keyEncryptionAlgorithm]
|
||||
* @property {string} [encryptedKey]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.Integer({ name: (names.version || "") }),
|
||||
KEKIdentifier.schema(names.kekid || {}),
|
||||
AlgorithmIdentifier.schema(names.keyEncryptionAlgorithm || {}),
|
||||
new asn1js.OctetString({ name: (names.encryptedKey || "") })
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"version",
|
||||
"kekid",
|
||||
"keyEncryptionAlgorithm",
|
||||
"encryptedKey"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
KEKRecipientInfo.schema({
|
||||
names: {
|
||||
version: "version",
|
||||
kekid: {
|
||||
names: {
|
||||
blockName: "kekid"
|
||||
}
|
||||
},
|
||||
keyEncryptionAlgorithm: {
|
||||
names: {
|
||||
blockName: "keyEncryptionAlgorithm"
|
||||
}
|
||||
},
|
||||
encryptedKey: "encryptedKey"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for KEKRecipientInfo");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.version = asn1.result.version.valueBlock.valueDec;
|
||||
this.kekid = new KEKIdentifier({ schema: asn1.result.kekid });
|
||||
this.keyEncryptionAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.keyEncryptionAlgorithm });
|
||||
this.encryptedKey = asn1.result.encryptedKey;
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: [
|
||||
new asn1js.Integer({ value: this.version }),
|
||||
this.kekid.toSchema(),
|
||||
this.keyEncryptionAlgorithm.toSchema(),
|
||||
this.encryptedKey
|
||||
]
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
return {
|
||||
version: this.version,
|
||||
kekid: this.kekid.toJSON(),
|
||||
keyEncryptionAlgorithm: this.keyEncryptionAlgorithm.toJSON(),
|
||||
encryptedKey: this.encryptedKey.toJSON()
|
||||
};
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
206
core/third-party/pkijs/KeyAgreeRecipientIdentifier.js
vendored
Normal file
206
core/third-party/pkijs/KeyAgreeRecipientIdentifier.js
vendored
Normal file
@@ -0,0 +1,206 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import IssuerAndSerialNumber from "./IssuerAndSerialNumber.js";
|
||||
import RecipientKeyIdentifier from "./RecipientKeyIdentifier.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5652
|
||||
*/
|
||||
export default class KeyAgreeRecipientIdentifier
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for KeyAgreeRecipientIdentifier class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {number}
|
||||
* @desc variant
|
||||
*/
|
||||
this.variant = getParametersValue(parameters, "variant", KeyAgreeRecipientIdentifier.defaultValues("variant"));
|
||||
/**
|
||||
* @type {*}
|
||||
* @desc values
|
||||
*/
|
||||
this.value = getParametersValue(parameters, "value", KeyAgreeRecipientIdentifier.defaultValues("value"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "variant":
|
||||
return (-1);
|
||||
case "value":
|
||||
return {};
|
||||
default:
|
||||
throw new Error(`Invalid member name for KeyAgreeRecipientIdentifier class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Compare values with default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
* @param {*} memberValue Value to compare with default value
|
||||
*/
|
||||
static compareWithDefault(memberName, memberValue)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "variant":
|
||||
return (memberValue === (-1));
|
||||
case "value":
|
||||
return (Object.keys(memberValue).length === 0);
|
||||
default:
|
||||
throw new Error(`Invalid member name for KeyAgreeRecipientIdentifier class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* KeyAgreeRecipientIdentifier ::= CHOICE {
|
||||
* issuerAndSerialNumber IssuerAndSerialNumber,
|
||||
* rKeyId [0] IMPLICIT RecipientKeyIdentifier }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [issuerAndSerialNumber]
|
||||
* @property {string} [rKeyId]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Choice({
|
||||
value: [
|
||||
IssuerAndSerialNumber.schema(names.issuerAndSerialNumber || {
|
||||
names: {
|
||||
blockName: (names.blockName || "")
|
||||
}
|
||||
}),
|
||||
new asn1js.Constructed({
|
||||
name: (names.blockName || ""),
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: RecipientKeyIdentifier.schema(names.rKeyId || {
|
||||
names: {
|
||||
blockName: (names.blockName || "")
|
||||
}
|
||||
}).valueBlock.value
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"blockName"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
KeyAgreeRecipientIdentifier.schema({
|
||||
names: {
|
||||
blockName: "blockName"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for KeyAgreeRecipientIdentifier");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
if(asn1.result.blockName.idBlock.tagClass === 1)
|
||||
{
|
||||
this.variant = 1;
|
||||
this.value = new IssuerAndSerialNumber({ schema: asn1.result.blockName });
|
||||
}
|
||||
else
|
||||
{
|
||||
this.variant = 2;
|
||||
|
||||
this.value = new RecipientKeyIdentifier({
|
||||
schema: new asn1js.Sequence({
|
||||
value: asn1.result.blockName.valueBlock.value
|
||||
})
|
||||
});
|
||||
}
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
switch(this.variant)
|
||||
{
|
||||
case 1:
|
||||
return this.value.toSchema();
|
||||
case 2:
|
||||
return new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: this.value.toSchema().valueBlock.value
|
||||
});
|
||||
default:
|
||||
return new asn1js.Any();
|
||||
}
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
const _object = {
|
||||
variant: this.variant
|
||||
};
|
||||
|
||||
if((this.variant === 1) || (this.variant === 2))
|
||||
_object.value = this.value.toJSON();
|
||||
|
||||
return _object;
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
290
core/third-party/pkijs/KeyAgreeRecipientInfo.js
vendored
Normal file
290
core/third-party/pkijs/KeyAgreeRecipientInfo.js
vendored
Normal file
@@ -0,0 +1,290 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import OriginatorIdentifierOrKey from "./OriginatorIdentifierOrKey.js";
|
||||
import AlgorithmIdentifier from "./AlgorithmIdentifier.js";
|
||||
import RecipientEncryptedKeys from "./RecipientEncryptedKeys.js";
|
||||
import Certificate from "./Certificate.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5652
|
||||
*/
|
||||
export default class KeyAgreeRecipientInfo
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for KeyAgreeRecipientInfo class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {number}
|
||||
* @desc version
|
||||
*/
|
||||
this.version = getParametersValue(parameters, "version", KeyAgreeRecipientInfo.defaultValues("version"));
|
||||
/**
|
||||
* @type {OriginatorIdentifierOrKey}
|
||||
* @desc originator
|
||||
*/
|
||||
this.originator = getParametersValue(parameters, "originator", KeyAgreeRecipientInfo.defaultValues("originator"));
|
||||
|
||||
if("ukm" in parameters)
|
||||
/**
|
||||
* @type {OctetString}
|
||||
* @desc ukm
|
||||
*/
|
||||
this.ukm = getParametersValue(parameters, "ukm", KeyAgreeRecipientInfo.defaultValues("ukm"));
|
||||
|
||||
/**
|
||||
* @type {AlgorithmIdentifier}
|
||||
* @desc keyEncryptionAlgorithm
|
||||
*/
|
||||
this.keyEncryptionAlgorithm = getParametersValue(parameters, "keyEncryptionAlgorithm", KeyAgreeRecipientInfo.defaultValues("keyEncryptionAlgorithm"));
|
||||
/**
|
||||
* @type {RecipientEncryptedKeys}
|
||||
* @desc recipientEncryptedKeys
|
||||
*/
|
||||
this.recipientEncryptedKeys = getParametersValue(parameters, "recipientEncryptedKeys", KeyAgreeRecipientInfo.defaultValues("recipientEncryptedKeys"));
|
||||
/**
|
||||
* @type {Certificate}
|
||||
* @desc recipientCertificate For some reasons we need to store recipient's certificate here
|
||||
*/
|
||||
this.recipientCertificate = getParametersValue(parameters, "recipientCertificate", KeyAgreeRecipientInfo.defaultValues("recipientCertificate"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "version":
|
||||
return 0;
|
||||
case "originator":
|
||||
return new OriginatorIdentifierOrKey();
|
||||
case "ukm":
|
||||
return new asn1js.OctetString();
|
||||
case "keyEncryptionAlgorithm":
|
||||
return new AlgorithmIdentifier();
|
||||
case "recipientEncryptedKeys":
|
||||
return new RecipientEncryptedKeys();
|
||||
case "recipientCertificate":
|
||||
return new Certificate();
|
||||
default:
|
||||
throw new Error(`Invalid member name for KeyAgreeRecipientInfo class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Compare values with default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
* @param {*} memberValue Value to compare with default value
|
||||
*/
|
||||
static compareWithDefault(memberName, memberValue)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "version":
|
||||
return (memberValue === 0);
|
||||
case "originator":
|
||||
return ((memberValue.variant === (-1)) && (("value" in memberValue) === false));
|
||||
case "ukm":
|
||||
return (memberValue.isEqual(KeyAgreeRecipientInfo.defaultValues("ukm")));
|
||||
case "keyEncryptionAlgorithm":
|
||||
return ((memberValue.algorithmId === "") && (("algorithmParams" in memberValue) === false));
|
||||
case "recipientEncryptedKeys":
|
||||
return (memberValue.encryptedKeys.length === 0);
|
||||
case "recipientCertificate":
|
||||
return false; // For now leave it as is
|
||||
default:
|
||||
throw new Error(`Invalid member name for KeyAgreeRecipientInfo class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* KeyAgreeRecipientInfo ::= SEQUENCE {
|
||||
* version CMSVersion, -- always set to 3
|
||||
* originator [0] EXPLICIT OriginatorIdentifierOrKey,
|
||||
* ukm [1] EXPLICIT UserKeyingMaterial OPTIONAL,
|
||||
* keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
|
||||
* recipientEncryptedKeys RecipientEncryptedKeys }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [version]
|
||||
* @property {string} [originator]
|
||||
* @property {string} [ukm]
|
||||
* @property {string} [keyEncryptionAlgorithm]
|
||||
* @property {string} [recipientEncryptedKeys]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: names.blockName || "",
|
||||
value: [
|
||||
new asn1js.Integer({ name: names.version || "" }),
|
||||
new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: [
|
||||
OriginatorIdentifierOrKey.schema(names.originator || {})
|
||||
]
|
||||
}),
|
||||
new asn1js.Constructed({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 1 // [1]
|
||||
},
|
||||
value: [new asn1js.OctetString({ name: names.ukm || "" })]
|
||||
}),
|
||||
AlgorithmIdentifier.schema(names.keyEncryptionAlgorithm || {}),
|
||||
RecipientEncryptedKeys.schema(names.recipientEncryptedKeys || {})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"version",
|
||||
"originator",
|
||||
"ukm",
|
||||
"keyEncryptionAlgorithm",
|
||||
"recipientEncryptedKeys"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
KeyAgreeRecipientInfo.schema({
|
||||
names: {
|
||||
version: "version",
|
||||
originator: {
|
||||
names: {
|
||||
blockName: "originator"
|
||||
}
|
||||
},
|
||||
ukm: "ukm",
|
||||
keyEncryptionAlgorithm: {
|
||||
names: {
|
||||
blockName: "keyEncryptionAlgorithm"
|
||||
}
|
||||
},
|
||||
recipientEncryptedKeys: {
|
||||
names: {
|
||||
blockName: "recipientEncryptedKeys"
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for KeyAgreeRecipientInfo");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.version = asn1.result.version.valueBlock.valueDec;
|
||||
this.originator = new OriginatorIdentifierOrKey({ schema: asn1.result.originator });
|
||||
|
||||
if("ukm" in asn1.result)
|
||||
this.ukm = asn1.result.ukm;
|
||||
|
||||
this.keyEncryptionAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.keyEncryptionAlgorithm });
|
||||
this.recipientEncryptedKeys = new RecipientEncryptedKeys({ schema: asn1.result.recipientEncryptedKeys });
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Create array for final sequence
|
||||
const outputArray = [];
|
||||
|
||||
outputArray.push(new asn1js.Integer({ value: this.version }));
|
||||
outputArray.push(new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: [this.originator.toSchema()]
|
||||
}));
|
||||
|
||||
if("ukm" in this)
|
||||
{
|
||||
outputArray.push(new asn1js.Constructed({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 1 // [1]
|
||||
},
|
||||
value: [this.ukm]
|
||||
}));
|
||||
}
|
||||
|
||||
outputArray.push(this.keyEncryptionAlgorithm.toSchema());
|
||||
outputArray.push(this.recipientEncryptedKeys.toSchema());
|
||||
//endregion
|
||||
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: outputArray
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
const _object = {
|
||||
version: this.version,
|
||||
originator: this.originator.toJSON()
|
||||
};
|
||||
|
||||
if("ukm" in this)
|
||||
_object.ukm = this.ukm.toJSON();
|
||||
|
||||
_object.keyEncryptionAlgorithm = this.keyEncryptionAlgorithm.toJSON();
|
||||
_object.recipientEncryptedKeys = this.recipientEncryptedKeys.toJSON();
|
||||
|
||||
return _object;
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
20
core/third-party/pkijs/KeyBag.js
vendored
Normal file
20
core/third-party/pkijs/KeyBag.js
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
import PrivateKeyInfo from "./PrivateKeyInfo.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5208
|
||||
*/
|
||||
export default class KeyBag extends PrivateKeyInfo
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for Attribute class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
super(parameters);
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
248
core/third-party/pkijs/KeyTransRecipientInfo.js
vendored
Normal file
248
core/third-party/pkijs/KeyTransRecipientInfo.js
vendored
Normal file
@@ -0,0 +1,248 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import AlgorithmIdentifier from "./AlgorithmIdentifier.js";
|
||||
import Certificate from "./Certificate.js";
|
||||
import RecipientIdentifier from "./RecipientIdentifier.js";
|
||||
import IssuerAndSerialNumber from "./IssuerAndSerialNumber.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5652
|
||||
*/
|
||||
export default class KeyTransRecipientInfo
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for KeyTransRecipientInfo class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {number}
|
||||
* @desc version
|
||||
*/
|
||||
this.version = getParametersValue(parameters, "version", KeyTransRecipientInfo.defaultValues("version"));
|
||||
/**
|
||||
* @type {RecipientIdentifier}
|
||||
* @desc rid
|
||||
*/
|
||||
this.rid = getParametersValue(parameters, "rid", KeyTransRecipientInfo.defaultValues("rid"));
|
||||
/**
|
||||
* @type {AlgorithmIdentifier}
|
||||
* @desc keyEncryptionAlgorithm
|
||||
*/
|
||||
this.keyEncryptionAlgorithm = getParametersValue(parameters, "keyEncryptionAlgorithm", KeyTransRecipientInfo.defaultValues("keyEncryptionAlgorithm"));
|
||||
/**
|
||||
* @type {OctetString}
|
||||
* @desc encryptedKey
|
||||
*/
|
||||
this.encryptedKey = getParametersValue(parameters, "encryptedKey", KeyTransRecipientInfo.defaultValues("encryptedKey"));
|
||||
/**
|
||||
* @type {Certificate}
|
||||
* @desc recipientCertificate For some reasons we need to store recipient's certificate here
|
||||
*/
|
||||
this.recipientCertificate = getParametersValue(parameters, "recipientCertificate", KeyTransRecipientInfo.defaultValues("recipientCertificate"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "version":
|
||||
return (-1);
|
||||
case "rid":
|
||||
return {};
|
||||
case "keyEncryptionAlgorithm":
|
||||
return new AlgorithmIdentifier();
|
||||
case "encryptedKey":
|
||||
return new asn1js.OctetString();
|
||||
case "recipientCertificate":
|
||||
return new Certificate();
|
||||
default:
|
||||
throw new Error(`Invalid member name for KeyTransRecipientInfo class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Compare values with default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
* @param {*} memberValue Value to compare with default value
|
||||
*/
|
||||
static compareWithDefault(memberName, memberValue)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "version":
|
||||
return (memberValue === KeyTransRecipientInfo.defaultValues("version"));
|
||||
case "rid":
|
||||
return (Object.keys(memberValue).length === 0);
|
||||
case "keyEncryptionAlgorithm":
|
||||
case "encryptedKey":
|
||||
return memberValue.isEqual(KeyTransRecipientInfo.defaultValues(memberName));
|
||||
case "recipientCertificate":
|
||||
return false; // For now we do not need to compare any values with the "recipientCertificate"
|
||||
default:
|
||||
throw new Error(`Invalid member name for KeyTransRecipientInfo class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* KeyTransRecipientInfo ::= SEQUENCE {
|
||||
* version CMSVersion, -- always set to 0 or 2
|
||||
* rid RecipientIdentifier,
|
||||
* keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
|
||||
* encryptedKey EncryptedKey }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [version]
|
||||
* @property {string} [rid]
|
||||
* @property {string} [keyEncryptionAlgorithm]
|
||||
* @property {string} [encryptedKey]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.Integer({ name: (names.version || "") }),
|
||||
RecipientIdentifier.schema(names.rid || {}),
|
||||
AlgorithmIdentifier.schema(names.keyEncryptionAlgorithm || {}),
|
||||
new asn1js.OctetString({ name: (names.encryptedKey || "") })
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"version",
|
||||
"rid",
|
||||
"keyEncryptionAlgorithm",
|
||||
"encryptedKey"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
KeyTransRecipientInfo.schema({
|
||||
names: {
|
||||
version: "version",
|
||||
rid: {
|
||||
names: {
|
||||
blockName: "rid"
|
||||
}
|
||||
},
|
||||
keyEncryptionAlgorithm: {
|
||||
names: {
|
||||
blockName: "keyEncryptionAlgorithm"
|
||||
}
|
||||
},
|
||||
encryptedKey: "encryptedKey"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for KeyTransRecipientInfo");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.version = asn1.result.version.valueBlock.valueDec;
|
||||
|
||||
if(asn1.result.rid.idBlock.tagClass === 3)
|
||||
this.rid = new asn1js.OctetString({ valueHex: asn1.result.rid.valueBlock.valueHex }); // SubjectKeyIdentifier
|
||||
else
|
||||
this.rid = new IssuerAndSerialNumber({ schema: asn1.result.rid });
|
||||
|
||||
this.keyEncryptionAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.keyEncryptionAlgorithm });
|
||||
this.encryptedKey = asn1.result.encryptedKey;
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Create array for output sequence
|
||||
const outputArray = [];
|
||||
|
||||
if(this.rid instanceof IssuerAndSerialNumber)
|
||||
{
|
||||
this.version = 0;
|
||||
|
||||
outputArray.push(new asn1js.Integer({ value: this.version }));
|
||||
outputArray.push(this.rid.toSchema());
|
||||
}
|
||||
else
|
||||
{
|
||||
this.version = 2;
|
||||
|
||||
outputArray.push(new asn1js.Integer({ value: this.version }));
|
||||
outputArray.push(new asn1js.Primitive({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
valueHex: this.rid.valueBlock.valueHex
|
||||
}));
|
||||
}
|
||||
|
||||
outputArray.push(this.keyEncryptionAlgorithm.toSchema());
|
||||
outputArray.push(this.encryptedKey);
|
||||
//endregion
|
||||
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: outputArray
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
return {
|
||||
version: this.version,
|
||||
rid: this.rid.toJSON(),
|
||||
keyEncryptionAlgorithm: this.keyEncryptionAlgorithm.toJSON(),
|
||||
encryptedKey: this.encryptedKey.toJSON()
|
||||
};
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
214
core/third-party/pkijs/MacData.js
vendored
Normal file
214
core/third-party/pkijs/MacData.js
vendored
Normal file
@@ -0,0 +1,214 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import DigestInfo from "./DigestInfo.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC7292
|
||||
*/
|
||||
export default class MacData
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for MacData class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {DigestInfo}
|
||||
* @desc mac
|
||||
*/
|
||||
this.mac = getParametersValue(parameters, "mac", MacData.defaultValues("mac"));
|
||||
/**
|
||||
* @type {OctetString}
|
||||
* @desc macSalt
|
||||
*/
|
||||
this.macSalt = getParametersValue(parameters, "macSalt", MacData.defaultValues("macSalt"));
|
||||
|
||||
if("iterations" in parameters)
|
||||
/**
|
||||
* @type {number}
|
||||
* @desc iterations
|
||||
*/
|
||||
this.iterations = getParametersValue(parameters, "iterations", MacData.defaultValues("iterations"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "mac":
|
||||
return new DigestInfo();
|
||||
case "macSalt":
|
||||
return new asn1js.OctetString();
|
||||
case "iterations":
|
||||
return 1;
|
||||
default:
|
||||
throw new Error(`Invalid member name for MacData class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Compare values with default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
* @param {*} memberValue Value to compare with default value
|
||||
*/
|
||||
static compareWithDefault(memberName, memberValue)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "mac":
|
||||
return ((DigestInfo.compareWithDefault("digestAlgorithm", memberValue.digestAlgorithm)) &&
|
||||
(DigestInfo.compareWithDefault("digest", memberValue.digest)));
|
||||
case "macSalt":
|
||||
return (memberValue.isEqual(MacData.defaultValues(memberName)));
|
||||
case "iterations":
|
||||
return (memberValue === MacData.defaultValues(memberName));
|
||||
default:
|
||||
throw new Error(`Invalid member name for MacData class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* MacData ::= SEQUENCE {
|
||||
* mac DigestInfo,
|
||||
* macSalt OCTET STRING,
|
||||
* iterations INTEGER DEFAULT 1
|
||||
* -- Note: The default is for historical reasons and its use is
|
||||
* -- deprecated. A higher value, like 1024 is recommended.
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [optional]
|
||||
* @property {string} [mac]
|
||||
* @property {string} [macSalt]
|
||||
* @property {string} [iterations]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
optional: (names.optional || true),
|
||||
value: [
|
||||
DigestInfo.schema(names.mac || {
|
||||
names: {
|
||||
blockName: "mac"
|
||||
}
|
||||
}),
|
||||
new asn1js.OctetString({ name: (names.macSalt || "macSalt") }),
|
||||
new asn1js.Integer({
|
||||
optional: true,
|
||||
name: (names.iterations || "iterations")
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"mac",
|
||||
"macSalt",
|
||||
"iterations"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
MacData.schema({
|
||||
names: {
|
||||
mac: {
|
||||
names: {
|
||||
blockName: "mac"
|
||||
}
|
||||
},
|
||||
macSalt: "macSalt",
|
||||
iterations: "iterations"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for MacData");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.mac = new DigestInfo({ schema: asn1.result.mac });
|
||||
this.macSalt = asn1.result.macSalt;
|
||||
|
||||
if("iterations" in asn1.result)
|
||||
this.iterations = asn1.result.iterations.valueBlock.valueDec;
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
const outputArray = [
|
||||
this.mac.toSchema(),
|
||||
this.macSalt
|
||||
];
|
||||
|
||||
if("iterations" in this)
|
||||
outputArray.push(new asn1js.Integer({ value: this.iterations }));
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
value: outputArray
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
const output = {
|
||||
mac: this.mac.toJSON(),
|
||||
macSalt: this.macSalt.toJSON()
|
||||
};
|
||||
|
||||
if("iterations" in this)
|
||||
output.iterations = this.iterations.toJSON();
|
||||
|
||||
return output;
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
171
core/third-party/pkijs/MessageImprint.js
vendored
Normal file
171
core/third-party/pkijs/MessageImprint.js
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import AlgorithmIdentifier from "./AlgorithmIdentifier.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC3161
|
||||
*/
|
||||
export default class MessageImprint
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for MessageImprint class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {AlgorithmIdentifier}
|
||||
* @desc hashAlgorithm
|
||||
*/
|
||||
this.hashAlgorithm = getParametersValue(parameters, "hashAlgorithm", MessageImprint.defaultValues("hashAlgorithm"));
|
||||
/**
|
||||
* @type {OctetString}
|
||||
* @desc hashedMessage
|
||||
*/
|
||||
this.hashedMessage = getParametersValue(parameters, "hashedMessage", MessageImprint.defaultValues("hashedMessage"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "hashAlgorithm":
|
||||
return new AlgorithmIdentifier();
|
||||
case "hashedMessage":
|
||||
return new asn1js.OctetString();
|
||||
default:
|
||||
throw new Error(`Invalid member name for MessageImprint class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Compare values with default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
* @param {*} memberValue Value to compare with default value
|
||||
*/
|
||||
static compareWithDefault(memberName, memberValue)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "hashAlgorithm":
|
||||
return ((memberValue.algorithmId === "") && (("algorithmParams" in memberValue) === false));
|
||||
case "hashedMessage":
|
||||
return (memberValue.isEqual(MessageImprint.defaultValues(memberName)) === 0);
|
||||
default:
|
||||
throw new Error(`Invalid member name for MessageImprint class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* MessageImprint ::= SEQUENCE {
|
||||
* hashAlgorithm AlgorithmIdentifier,
|
||||
* hashedMessage OCTET STRING }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [hashAlgorithm]
|
||||
* @property {string} [hashedMessage]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
AlgorithmIdentifier.schema(names.hashAlgorithm || {}),
|
||||
new asn1js.OctetString({ name: (names.hashedMessage || "") })
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"hashAlgorithm",
|
||||
"hashedMessage"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
MessageImprint.schema({
|
||||
names: {
|
||||
hashAlgorithm: {
|
||||
names: {
|
||||
blockName: "hashAlgorithm"
|
||||
}
|
||||
},
|
||||
hashedMessage: "hashedMessage"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for MessageImprint");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.hashAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.hashAlgorithm });
|
||||
this.hashedMessage = asn1.result.hashedMessage;
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: [
|
||||
this.hashAlgorithm.toSchema(),
|
||||
this.hashedMessage
|
||||
]
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
return {
|
||||
hashAlgorithm: this.hashAlgorithm.toJSON(),
|
||||
hashedMessage: this.hashedMessage.toJSON()
|
||||
};
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
207
core/third-party/pkijs/NameConstraints.js
vendored
Normal file
207
core/third-party/pkijs/NameConstraints.js
vendored
Normal file
@@ -0,0 +1,207 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import GeneralSubtree from "./GeneralSubtree.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5280
|
||||
*/
|
||||
export default class NameConstraints
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for NameConstraints class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
if("permittedSubtrees" in parameters)
|
||||
/**
|
||||
* @type {Array.<GeneralSubtree>}
|
||||
* @desc permittedSubtrees
|
||||
*/
|
||||
this.permittedSubtrees = getParametersValue(parameters, "permittedSubtrees", NameConstraints.defaultValues("permittedSubtrees"));
|
||||
|
||||
if("excludedSubtrees" in parameters)
|
||||
/**
|
||||
* @type {Array.<GeneralSubtree>}
|
||||
* @desc excludedSubtrees
|
||||
*/
|
||||
this.excludedSubtrees = getParametersValue(parameters, "excludedSubtrees", NameConstraints.defaultValues("excludedSubtrees"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "permittedSubtrees":
|
||||
return [];
|
||||
case "excludedSubtrees":
|
||||
return [];
|
||||
default:
|
||||
throw new Error(`Invalid member name for NameConstraints class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* NameConstraints ::= SEQUENCE {
|
||||
* permittedSubtrees [0] GeneralSubtrees OPTIONAL,
|
||||
* excludedSubtrees [1] GeneralSubtrees OPTIONAL }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [permittedSubtrees]
|
||||
* @property {string} [excludedSubtrees]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.Constructed({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: [
|
||||
new asn1js.Repeated({
|
||||
name: (names.permittedSubtrees || ""),
|
||||
value: GeneralSubtree.schema()
|
||||
})
|
||||
]
|
||||
}),
|
||||
new asn1js.Constructed({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 1 // [1]
|
||||
},
|
||||
value: [
|
||||
new asn1js.Repeated({
|
||||
name: (names.excludedSubtrees || ""),
|
||||
value: GeneralSubtree.schema()
|
||||
})
|
||||
]
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"permittedSubtrees",
|
||||
"excludedSubtrees"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
NameConstraints.schema({
|
||||
names: {
|
||||
permittedSubtrees: "permittedSubtrees",
|
||||
excludedSubtrees: "excludedSubtrees"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for NameConstraints");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
if("permittedSubtrees" in asn1.result)
|
||||
this.permittedSubtrees = Array.from(asn1.result.permittedSubtrees, element => new GeneralSubtree({ schema: element }));
|
||||
|
||||
if("excludedSubtrees" in asn1.result)
|
||||
this.excludedSubtrees = Array.from(asn1.result.excludedSubtrees, element => new GeneralSubtree({ schema: element }));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Create array for output sequence
|
||||
const outputArray = [];
|
||||
|
||||
if("permittedSubtrees" in this)
|
||||
{
|
||||
outputArray.push(new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: Array.from(this.permittedSubtrees, element => element.toSchema())
|
||||
}));
|
||||
}
|
||||
|
||||
if("excludedSubtrees" in this)
|
||||
{
|
||||
outputArray.push(new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 1 // [1]
|
||||
},
|
||||
value: Array.from(this.excludedSubtrees, element => element.toSchema())
|
||||
}));
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: outputArray
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
const object = {};
|
||||
|
||||
if("permittedSubtrees" in this)
|
||||
object.permittedSubtrees = Array.from(this.permittedSubtrees, element => element.toJSON());
|
||||
|
||||
if("excludedSubtrees" in this)
|
||||
object.excludedSubtrees = Array.from(this.excludedSubtrees, element => element.toJSON());
|
||||
|
||||
return object;
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
304
core/third-party/pkijs/OCSPRequest.js
vendored
Normal file
304
core/third-party/pkijs/OCSPRequest.js
vendored
Normal file
@@ -0,0 +1,304 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import { getEngine } from "./common.js";
|
||||
import TBSRequest from "./TBSRequest.js";
|
||||
import Signature from "./Signature.js";
|
||||
import Request from "./Request.js";
|
||||
import CertID from "./CertID.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC6960
|
||||
*/
|
||||
export default class OCSPRequest
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for OCSPRequest class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {TBSRequest}
|
||||
* @desc tbsRequest
|
||||
*/
|
||||
this.tbsRequest = getParametersValue(parameters, "tbsRequest", OCSPRequest.defaultValues("tbsRequest"));
|
||||
|
||||
if("optionalSignature" in parameters)
|
||||
/**
|
||||
* @type {Signature}
|
||||
* @desc optionalSignature
|
||||
*/
|
||||
this.optionalSignature = getParametersValue(parameters, "optionalSignature", OCSPRequest.defaultValues("optionalSignature"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "tbsRequest":
|
||||
return new TBSRequest();
|
||||
case "optionalSignature":
|
||||
return new Signature();
|
||||
default:
|
||||
throw new Error(`Invalid member name for OCSPRequest class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Compare values with default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
* @param {*} memberValue Value to compare with default value
|
||||
*/
|
||||
static compareWithDefault(memberName, memberValue)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "tbsRequest":
|
||||
// noinspection OverlyComplexBooleanExpressionJS
|
||||
return ((TBSRequest.compareWithDefault("tbs", memberValue.tbs)) &&
|
||||
(TBSRequest.compareWithDefault("version", memberValue.version)) &&
|
||||
(TBSRequest.compareWithDefault("requestorName", memberValue.requestorName)) &&
|
||||
(TBSRequest.compareWithDefault("requestList", memberValue.requestList)) &&
|
||||
(TBSRequest.compareWithDefault("requestExtensions", memberValue.requestExtensions)));
|
||||
case "optionalSignature":
|
||||
return ((Signature.compareWithDefault("signatureAlgorithm", memberValue.signatureAlgorithm)) &&
|
||||
(Signature.compareWithDefault("signature", memberValue.signature)) &&
|
||||
(Signature.compareWithDefault("certs", memberValue.certs)));
|
||||
default:
|
||||
throw new Error(`Invalid member name for OCSPRequest class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* OCSPRequest ::= SEQUENCE {
|
||||
* tbsRequest TBSRequest,
|
||||
* optionalSignature [0] EXPLICIT Signature OPTIONAL }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [tbsRequest]
|
||||
* @property {string} [optionalSignature]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: names.blockName || "OCSPRequest",
|
||||
value: [
|
||||
TBSRequest.schema(names.tbsRequest || {
|
||||
names: {
|
||||
blockName: "tbsRequest"
|
||||
}
|
||||
}),
|
||||
new asn1js.Constructed({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: [
|
||||
Signature.schema(names.optionalSignature || {
|
||||
names: {
|
||||
blockName: "optionalSignature"
|
||||
}
|
||||
})
|
||||
]
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"tbsRequest",
|
||||
"optionalSignature"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
OCSPRequest.schema()
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for OCSPRequest");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.tbsRequest = new TBSRequest({ schema: asn1.result.tbsRequest });
|
||||
if("optionalSignature" in asn1.result)
|
||||
this.optionalSignature = new Signature({ schema: asn1.result.optionalSignature });
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @param {boolean} encodeFlag If param equal to false then create TBS schema via decoding stored value. In othe case create TBS schema via assembling from TBS parts.
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema(encodeFlag = false)
|
||||
{
|
||||
//region Create array for output sequence
|
||||
const outputArray = [];
|
||||
|
||||
outputArray.push(this.tbsRequest.toSchema(encodeFlag));
|
||||
if("optionalSignature" in this)
|
||||
outputArray.push(this.optionalSignature.toSchema());
|
||||
//endregion
|
||||
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: outputArray
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
const _object = {
|
||||
tbsRequest: this.tbsRequest.toJSON()
|
||||
};
|
||||
|
||||
if("optionalSignature" in this)
|
||||
_object.optionalSignature = this.optionalSignature.toJSON();
|
||||
|
||||
return _object;
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Making OCSP Request for specific certificate
|
||||
* @param {Certificate} certificate Certificate making OCSP Request for
|
||||
* @param {Object} parameters Additional parameters
|
||||
* @returns {Promise}
|
||||
*/
|
||||
createForCertificate(certificate, parameters)
|
||||
{
|
||||
//region Initial variables
|
||||
let sequence = Promise.resolve();
|
||||
|
||||
const certID = new CertID();
|
||||
//endregion
|
||||
|
||||
//region Create OCSP certificate identifier for the certificate
|
||||
sequence = sequence.then(() =>
|
||||
certID.createForCertificate(certificate, parameters)
|
||||
);
|
||||
//endregion
|
||||
|
||||
//region Make final request data
|
||||
sequence = sequence.then(() =>
|
||||
{
|
||||
this.tbsRequest = new TBSRequest({
|
||||
requestList: [
|
||||
new Request({
|
||||
reqCert: certID
|
||||
})
|
||||
]
|
||||
});
|
||||
}, error =>
|
||||
Promise.reject(error)
|
||||
);
|
||||
//endregion
|
||||
|
||||
return sequence;
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Make signature for current OCSP Request
|
||||
* @param {Object} privateKey Private key for "subjectPublicKeyInfo" structure
|
||||
* @param {string} [hashAlgorithm] Hashing algorithm. Default SHA-1
|
||||
* @returns {Promise}
|
||||
*/
|
||||
sign(privateKey, hashAlgorithm = "SHA-1")
|
||||
{
|
||||
//region Initial checking
|
||||
//region Check private key
|
||||
if(typeof privateKey === "undefined")
|
||||
return Promise.reject("Need to provide a private key for signing");
|
||||
//endregion
|
||||
|
||||
//region Check that "optionalSignature" exists in the current request
|
||||
if(("optionalSignature" in this) === false)
|
||||
return Promise.reject("Need to create \"optionalSignature\" field before signing");
|
||||
//endregion
|
||||
//endregion
|
||||
|
||||
//region Initial variables
|
||||
let sequence = Promise.resolve();
|
||||
let parameters;
|
||||
|
||||
let tbs;
|
||||
|
||||
const engine = getEngine();
|
||||
//endregion
|
||||
|
||||
//region Get a "default parameters" for current algorithm and set correct signature algorithm
|
||||
sequence = sequence.then(() => engine.subtle.getSignatureParameters(privateKey, hashAlgorithm));
|
||||
|
||||
sequence = sequence.then(result =>
|
||||
{
|
||||
parameters = result.parameters;
|
||||
this.optionalSignature.signatureAlgorithm = result.signatureAlgorithm;
|
||||
});
|
||||
//endregion
|
||||
|
||||
//region Create TBS data for signing
|
||||
sequence = sequence.then(() =>
|
||||
{
|
||||
tbs = this.tbsRequest.toSchema(true).toBER(false);
|
||||
});
|
||||
//endregion
|
||||
|
||||
//region Signing TBS data on provided private key
|
||||
sequence = sequence.then(() => engine.subtle.signWithPrivateKey(tbs, privateKey, parameters));
|
||||
|
||||
sequence = sequence.then(result =>
|
||||
{
|
||||
this.optionalSignature.signature = new asn1js.BitString({ valueHex: result });
|
||||
});
|
||||
//endregion
|
||||
|
||||
return sequence;
|
||||
}
|
||||
//**********************************************************************************
|
||||
verify()
|
||||
{
|
||||
// TODO: Create the function
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
299
core/third-party/pkijs/OCSPResponse.js
vendored
Normal file
299
core/third-party/pkijs/OCSPResponse.js
vendored
Normal file
@@ -0,0 +1,299 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import ResponseBytes from "./ResponseBytes.js";
|
||||
import BasicOCSPResponse from "./BasicOCSPResponse.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC6960
|
||||
*/
|
||||
export default class OCSPResponse
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for OCSPResponse class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {Enumerated}
|
||||
* @desc responseStatus
|
||||
*/
|
||||
this.responseStatus = getParametersValue(parameters, "responseStatus", OCSPResponse.defaultValues("responseStatus"));
|
||||
|
||||
if("responseBytes" in parameters)
|
||||
/**
|
||||
* @type {ResponseBytes}
|
||||
* @desc responseBytes
|
||||
*/
|
||||
this.responseBytes = getParametersValue(parameters, "responseBytes", OCSPResponse.defaultValues("responseBytes"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "responseStatus":
|
||||
return new asn1js.Enumerated();
|
||||
case "responseBytes":
|
||||
return new ResponseBytes();
|
||||
default:
|
||||
throw new Error(`Invalid member name for OCSPResponse class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Compare values with default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
* @param {*} memberValue Value to compare with default value
|
||||
*/
|
||||
static compareWithDefault(memberName, memberValue)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "responseStatus":
|
||||
return (memberValue.isEqual(OCSPResponse.defaultValues(memberName)));
|
||||
case "responseBytes":
|
||||
return ((ResponseBytes.compareWithDefault("responseType", memberValue.responseType)) &&
|
||||
(ResponseBytes.compareWithDefault("response", memberValue.response)));
|
||||
default:
|
||||
throw new Error(`Invalid member name for OCSPResponse class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* OCSPResponse ::= SEQUENCE {
|
||||
* responseStatus OCSPResponseStatus,
|
||||
* responseBytes [0] EXPLICIT ResponseBytes OPTIONAL }
|
||||
*
|
||||
* OCSPResponseStatus ::= ENUMERATED {
|
||||
* successful (0), -- Response has valid confirmations
|
||||
* malformedRequest (1), -- Illegal confirmation request
|
||||
* internalError (2), -- Internal error in issuer
|
||||
* tryLater (3), -- Try again later
|
||||
* -- (4) is not used
|
||||
* sigRequired (5), -- Must sign the request
|
||||
* unauthorized (6) -- Request unauthorized
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [responseStatus]
|
||||
* @property {string} [responseBytes]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || "OCSPResponse"),
|
||||
value: [
|
||||
new asn1js.Enumerated({ name: (names.responseStatus || "responseStatus") }),
|
||||
new asn1js.Constructed({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: [
|
||||
ResponseBytes.schema(names.responseBytes || {
|
||||
names: {
|
||||
blockName: "responseBytes"
|
||||
}
|
||||
})
|
||||
]
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"responseStatus",
|
||||
"responseBytes"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
OCSPResponse.schema()
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for OCSPResponse");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.responseStatus = asn1.result.responseStatus;
|
||||
if("responseBytes" in asn1.result)
|
||||
this.responseBytes = new ResponseBytes({ schema: asn1.result.responseBytes });
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Create array for output sequence
|
||||
const outputArray = [];
|
||||
|
||||
outputArray.push(this.responseStatus);
|
||||
if("responseBytes" in this)
|
||||
{
|
||||
outputArray.push(new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: [this.responseBytes.toSchema()]
|
||||
}));
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: outputArray
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
const _object = {
|
||||
responseStatus: this.responseStatus.toJSON()
|
||||
};
|
||||
|
||||
if("responseBytes" in this)
|
||||
_object.responseBytes = this.responseBytes.toJSON();
|
||||
|
||||
return _object;
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Get OCSP response status for specific certificate
|
||||
* @param {Certificate} certificate
|
||||
* @param {Certificate} issuerCertificate
|
||||
* @returns {*}
|
||||
*/
|
||||
getCertificateStatus(certificate, issuerCertificate)
|
||||
{
|
||||
//region Initial variables
|
||||
let basicResponse;
|
||||
|
||||
const result = {
|
||||
isForCertificate: false,
|
||||
status: 2 // 0 = good, 1 = revoked, 2 = unknown
|
||||
};
|
||||
//endregion
|
||||
|
||||
//region Check that "ResponseBytes" contain "OCSP_BASIC_RESPONSE"
|
||||
if(("responseBytes" in this) === false)
|
||||
return result;
|
||||
|
||||
if(this.responseBytes.responseType !== "1.3.6.1.5.5.7.48.1.1") // id-pkix-ocsp-basic
|
||||
return result;
|
||||
|
||||
try
|
||||
{
|
||||
const asn1Basic = asn1js.fromBER(this.responseBytes.response.valueBlock.valueHex);
|
||||
basicResponse = new BasicOCSPResponse({ schema: asn1Basic.result });
|
||||
}
|
||||
catch(ex)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
//endregion
|
||||
|
||||
return basicResponse.getCertificateStatus(certificate, issuerCertificate);
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Make a signature for current OCSP Response
|
||||
* @param {Object} privateKey Private key for "subjectPublicKeyInfo" structure
|
||||
* @param {string} [hashAlgorithm] Hashing algorithm. Default SHA-1
|
||||
* @returns {Promise}
|
||||
*/
|
||||
sign(privateKey, hashAlgorithm)
|
||||
{
|
||||
//region Check that ResponseData has type BasicOCSPResponse and sign it
|
||||
if(this.responseBytes.responseType === "1.3.6.1.5.5.7.48.1.1")
|
||||
{
|
||||
const asn1 = asn1js.fromBER(this.responseBytes.response.valueBlock.valueHex);
|
||||
const basicResponse = new BasicOCSPResponse({ schema: asn1.result });
|
||||
|
||||
return basicResponse.sign(privateKey, hashAlgorithm);
|
||||
}
|
||||
|
||||
return Promise.reject(`Unknown ResponseBytes type: ${this.responseBytes.responseType}`);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Verify current OCSP Response
|
||||
* @param {Certificate|null} issuerCertificate In order to decrease size of resp issuer cert could be ommited. In such case you need manually provide it.
|
||||
* @returns {Promise}
|
||||
*/
|
||||
verify(issuerCertificate = null)
|
||||
{
|
||||
//region Check that ResponseBytes exists in the object
|
||||
if(("responseBytes" in this) === false)
|
||||
return Promise.reject("Empty ResponseBytes field");
|
||||
//endregion
|
||||
|
||||
//region Check that ResponceData has type BasicOCSPResponse and verify it
|
||||
if(this.responseBytes.responseType === "1.3.6.1.5.5.7.48.1.1")
|
||||
{
|
||||
const asn1 = asn1js.fromBER(this.responseBytes.response.valueBlock.valueHex);
|
||||
const basicResponse = new BasicOCSPResponse({ schema: asn1.result });
|
||||
|
||||
if(issuerCertificate !== null)
|
||||
{
|
||||
if(("certs" in basicResponse) === false)
|
||||
basicResponse.certs = [];
|
||||
|
||||
basicResponse.certs.push(issuerCertificate);
|
||||
}
|
||||
|
||||
return basicResponse.verify();
|
||||
}
|
||||
|
||||
return Promise.reject(`Unknown ResponseBytes type: ${this.responseBytes.responseType}`);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
228
core/third-party/pkijs/OriginatorIdentifierOrKey.js
vendored
Normal file
228
core/third-party/pkijs/OriginatorIdentifierOrKey.js
vendored
Normal file
@@ -0,0 +1,228 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import IssuerAndSerialNumber from "./IssuerAndSerialNumber.js";
|
||||
import OriginatorPublicKey from "./OriginatorPublicKey.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5652
|
||||
*/
|
||||
export default class OriginatorIdentifierOrKey
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for OriginatorIdentifierOrKey class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {number}
|
||||
* @desc variant
|
||||
*/
|
||||
this.variant = getParametersValue(parameters, "variant", OriginatorIdentifierOrKey.defaultValues("variant"));
|
||||
|
||||
if("value" in parameters)
|
||||
/**
|
||||
* @type {IssuerAndSerialNumber|OctetString|OriginatorPublicKey}
|
||||
* @desc value
|
||||
*/
|
||||
this.value = getParametersValue(parameters, "value", OriginatorIdentifierOrKey.defaultValues("value"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "variant":
|
||||
return (-1);
|
||||
case "value":
|
||||
return {};
|
||||
default:
|
||||
throw new Error(`Invalid member name for OriginatorIdentifierOrKey class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Compare values with default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
* @param {*} memberValue Value to compare with default value
|
||||
*/
|
||||
static compareWithDefault(memberName, memberValue)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "variant":
|
||||
return (memberValue === (-1));
|
||||
case "value":
|
||||
return (Object.keys(memberValue).length === 0);
|
||||
default:
|
||||
throw new Error(`Invalid member name for OriginatorIdentifierOrKey class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* OriginatorIdentifierOrKey ::= CHOICE {
|
||||
* issuerAndSerialNumber IssuerAndSerialNumber,
|
||||
* subjectKeyIdentifier [0] SubjectKeyIdentifier,
|
||||
* originatorKey [1] OriginatorPublicKey }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Choice({
|
||||
value: [
|
||||
IssuerAndSerialNumber.schema({
|
||||
names: {
|
||||
blockName: (names.blockName || "")
|
||||
}
|
||||
}),
|
||||
new asn1js.Primitive({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
name: (names.blockName || "")
|
||||
}),
|
||||
new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 1 // [1]
|
||||
},
|
||||
name: (names.blockName || ""),
|
||||
value: OriginatorPublicKey.schema().valueBlock.value
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"blockName"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
OriginatorIdentifierOrKey.schema({
|
||||
names: {
|
||||
blockName: "blockName"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for OriginatorIdentifierOrKey");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
if(asn1.result.blockName.idBlock.tagClass === 1)
|
||||
{
|
||||
this.variant = 1;
|
||||
this.value = new IssuerAndSerialNumber({ schema: asn1.result.blockName });
|
||||
}
|
||||
else
|
||||
{
|
||||
if(asn1.result.blockName.idBlock.tagNumber === 0)
|
||||
{
|
||||
//region Create "OCTETSTRING" from "ASN1_PRIMITIVE"
|
||||
asn1.result.blockName.idBlock.tagClass = 1; // UNIVERSAL
|
||||
asn1.result.blockName.idBlock.tagNumber = 4; // OCTETSTRING
|
||||
//endregion
|
||||
|
||||
this.variant = 2;
|
||||
this.value = asn1.result.blockName;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.variant = 3;
|
||||
this.value = new OriginatorPublicKey({
|
||||
schema: new asn1js.Sequence({
|
||||
value: asn1.result.blockName.valueBlock.value
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
switch(this.variant)
|
||||
{
|
||||
case 1:
|
||||
return this.value.toSchema();
|
||||
case 2:
|
||||
this.value.idBlock.tagClass = 3; // CONTEXT-SPECIFIC
|
||||
this.value.idBlock.tagNumber = 0; // [0]
|
||||
|
||||
return this.value;
|
||||
case 3:
|
||||
{
|
||||
const _schema = this.value.toSchema();
|
||||
|
||||
_schema.idBlock.tagClass = 3; // CONTEXT-SPECIFIC
|
||||
_schema.idBlock.tagNumber = 1; // [1]
|
||||
|
||||
return _schema;
|
||||
}
|
||||
default:
|
||||
return new asn1js.Any();
|
||||
}
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
const _object = {
|
||||
variant: this.variant
|
||||
};
|
||||
|
||||
if((this.variant === 1) || (this.variant === 2) || (this.variant === 3))
|
||||
_object.value = this.value.toJSON();
|
||||
|
||||
return _object;
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
228
core/third-party/pkijs/OriginatorInfo.js
vendored
Normal file
228
core/third-party/pkijs/OriginatorInfo.js
vendored
Normal file
@@ -0,0 +1,228 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import CertificateSet from "./CertificateSet.js";
|
||||
import RevocationInfoChoices from "./RevocationInfoChoices.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5652
|
||||
*/
|
||||
export default class OriginatorInfo
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for OriginatorInfo class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
if("certs" in parameters)
|
||||
/**
|
||||
* @type {CertificateSet}
|
||||
* @desc certs
|
||||
*/
|
||||
this.certs = getParametersValue(parameters, "certs", OriginatorInfo.defaultValues("certs"));
|
||||
|
||||
if("crls" in parameters)
|
||||
/**
|
||||
* @type {RevocationInfoChoices}
|
||||
* @desc crls
|
||||
*/
|
||||
this.crls = getParametersValue(parameters, "crls", OriginatorInfo.defaultValues("crls"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "certs":
|
||||
return new CertificateSet();
|
||||
case "crls":
|
||||
return new RevocationInfoChoices();
|
||||
default:
|
||||
throw new Error(`Invalid member name for OriginatorInfo class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Compare values with default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
* @param {*} memberValue Value to compare with default value
|
||||
*/
|
||||
static compareWithDefault(memberName, memberValue)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "certs":
|
||||
return (memberValue.certificates.length === 0);
|
||||
case "crls":
|
||||
return ((memberValue.crls.length === 0) && (memberValue.otherRevocationInfos.length === 0));
|
||||
default:
|
||||
throw new Error(`Invalid member name for OriginatorInfo class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* OriginatorInfo ::= SEQUENCE {
|
||||
* certs [0] IMPLICIT CertificateSet OPTIONAL,
|
||||
* crls [1] IMPLICIT RevocationInfoChoices OPTIONAL }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [certs]
|
||||
* @property {string} [crls]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.Constructed({
|
||||
name: (names.certs || ""),
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: CertificateSet.schema().valueBlock.value
|
||||
}),
|
||||
new asn1js.Constructed({
|
||||
name: (names.crls || ""),
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 1 // [1]
|
||||
},
|
||||
value: RevocationInfoChoices.schema().valueBlock.value
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"certs",
|
||||
"crls"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
OriginatorInfo.schema({
|
||||
names: {
|
||||
certs: "certs",
|
||||
crls: "crls"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for OriginatorInfo");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
if("certs" in asn1.result)
|
||||
{
|
||||
this.certs = new CertificateSet({
|
||||
schema: new asn1js.Set({
|
||||
value: asn1.result.certs.valueBlock.value
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
if("crls" in asn1.result)
|
||||
{
|
||||
this.crls = new RevocationInfoChoices({
|
||||
schema: new asn1js.Set({
|
||||
value: asn1.result.crls.valueBlock.value
|
||||
})
|
||||
});
|
||||
}
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
const sequenceValue = [];
|
||||
|
||||
if("certs" in this)
|
||||
{
|
||||
sequenceValue.push(new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: this.certs.toSchema().valueBlock.value
|
||||
}));
|
||||
}
|
||||
|
||||
if("crls" in this)
|
||||
{
|
||||
sequenceValue.push(new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 1 // [1]
|
||||
},
|
||||
value: this.crls.toSchema().valueBlock.value
|
||||
}));
|
||||
}
|
||||
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: sequenceValue
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
const object = {};
|
||||
|
||||
if("certs" in this)
|
||||
object.certs = this.certs.toJSON();
|
||||
|
||||
if("crls" in this)
|
||||
object.crls = this.crls.toJSON();
|
||||
|
||||
return object;
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
170
core/third-party/pkijs/OriginatorPublicKey.js
vendored
Normal file
170
core/third-party/pkijs/OriginatorPublicKey.js
vendored
Normal file
@@ -0,0 +1,170 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import AlgorithmIdentifier from "./AlgorithmIdentifier.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5652
|
||||
*/
|
||||
export default class OriginatorPublicKey
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for OriginatorPublicKey class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {AlgorithmIdentifier}
|
||||
* @desc algorithm
|
||||
*/
|
||||
this.algorithm = getParametersValue(parameters, "algorithm", OriginatorPublicKey.defaultValues("algorithm"));
|
||||
/**
|
||||
* @type {BitString}
|
||||
* @desc publicKey
|
||||
*/
|
||||
this.publicKey = getParametersValue(parameters, "publicKey", OriginatorPublicKey.defaultValues("publicKey"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "algorithm":
|
||||
return new AlgorithmIdentifier();
|
||||
case "publicKey":
|
||||
return new asn1js.BitString();
|
||||
default:
|
||||
throw new Error(`Invalid member name for OriginatorPublicKey class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Compare values with default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
* @param {*} memberValue Value to compare with default value
|
||||
*/
|
||||
static compareWithDefault(memberName, memberValue)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "algorithm":
|
||||
case "publicKey":
|
||||
return (memberValue.isEqual(OriginatorPublicKey.defaultValues(memberName)));
|
||||
default:
|
||||
throw new Error(`Invalid member name for OriginatorPublicKey class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* OriginatorPublicKey ::= SEQUENCE {
|
||||
* algorithm AlgorithmIdentifier,
|
||||
* publicKey BIT STRING }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [algorithm]
|
||||
* @property {string} [publicKey]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
AlgorithmIdentifier.schema(names.algorithm || {}),
|
||||
new asn1js.BitString({ name: (names.publicKey || "") })
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"algorithm",
|
||||
"publicKey"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
OriginatorPublicKey.schema({
|
||||
names: {
|
||||
algorithm: {
|
||||
names: {
|
||||
blockName: "algorithm"
|
||||
}
|
||||
},
|
||||
publicKey: "publicKey"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for OriginatorPublicKey");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.algorithm = new AlgorithmIdentifier({ schema: asn1.result.algorithm });
|
||||
this.publicKey = asn1.result.publicKey;
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: [
|
||||
this.algorithm.toSchema(),
|
||||
this.publicKey
|
||||
]
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
return {
|
||||
algorithm: this.algorithm.toJSON(),
|
||||
publicKey: this.publicKey.toJSON()
|
||||
};
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
147
core/third-party/pkijs/OtherCertificateFormat.js
vendored
Normal file
147
core/third-party/pkijs/OtherCertificateFormat.js
vendored
Normal file
@@ -0,0 +1,147 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5652
|
||||
*/
|
||||
export default class OtherCertificateFormat
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for OtherCertificateFormat class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {string}
|
||||
* @desc otherCertFormat
|
||||
*/
|
||||
this.otherCertFormat = getParametersValue(parameters, "otherCertFormat", OtherCertificateFormat.defaultValues("otherCertFormat"));
|
||||
/**
|
||||
* @type {Any}
|
||||
* @desc otherCert
|
||||
*/
|
||||
this.otherCert = getParametersValue(parameters, "otherCert", OtherCertificateFormat.defaultValues("otherCert"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "otherCertFormat":
|
||||
return "";
|
||||
case "otherCert":
|
||||
return new asn1js.Any();
|
||||
default:
|
||||
throw new Error(`Invalid member name for OtherCertificateFormat class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* OtherCertificateFormat ::= SEQUENCE {
|
||||
* otherCertFormat OBJECT IDENTIFIER,
|
||||
* otherCert ANY DEFINED BY otherCertFormat }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [otherCertFormat]
|
||||
* @property {string} [otherCert]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.ObjectIdentifier({ name: (names.otherCertFormat || "otherCertFormat") }),
|
||||
new asn1js.Any({ name: (names.otherCert || "otherCert") })
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"otherCertFormat",
|
||||
"otherCert"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
OtherCertificateFormat.schema()
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for OtherCertificateFormat");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.otherCertFormat = asn1.result.otherCertFormat.valueBlock.toString();
|
||||
this.otherCert = asn1.result.otherCert;
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: [
|
||||
new asn1js.ObjectIdentifier({ value: this.otherCertFormat }),
|
||||
this.otherCert
|
||||
]
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
const object = {
|
||||
otherCertFormat: this.otherCertFormat
|
||||
};
|
||||
|
||||
if(!(this.otherCert instanceof asn1js.Any))
|
||||
object.otherCert = this.otherCert.toJSON();
|
||||
|
||||
return object;
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
185
core/third-party/pkijs/OtherKeyAttribute.js
vendored
Normal file
185
core/third-party/pkijs/OtherKeyAttribute.js
vendored
Normal file
@@ -0,0 +1,185 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5652
|
||||
*/
|
||||
export default class OtherKeyAttribute
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for OtherKeyAttribute class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {string}
|
||||
* @desc keyAttrId
|
||||
*/
|
||||
this.keyAttrId = getParametersValue(parameters, "keyAttrId", OtherKeyAttribute.defaultValues("keyAttrId"));
|
||||
|
||||
if("keyAttr" in parameters)
|
||||
/**
|
||||
* @type {*}
|
||||
* @desc keyAttr
|
||||
*/
|
||||
this.keyAttr = getParametersValue(parameters, "keyAttr", OtherKeyAttribute.defaultValues("keyAttr"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "keyAttrId":
|
||||
return "";
|
||||
case "keyAttr":
|
||||
return {};
|
||||
default:
|
||||
throw new Error(`Invalid member name for OtherKeyAttribute class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Compare values with default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
* @param {*} memberValue Value to compare with default value
|
||||
*/
|
||||
static compareWithDefault(memberName, memberValue)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "keyAttrId":
|
||||
return (memberValue === "");
|
||||
case "keyAttr":
|
||||
return (Object.keys(memberValue).length === 0);
|
||||
default:
|
||||
throw new Error(`Invalid member name for OtherKeyAttribute class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* OtherKeyAttribute ::= SEQUENCE {
|
||||
* keyAttrId OBJECT IDENTIFIER,
|
||||
* keyAttr ANY DEFINED BY keyAttrId OPTIONAL }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [optional]
|
||||
* @property {string} [keyAttrId]
|
||||
* @property {string} [keyAttr]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
optional: (names.optional || true),
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.ObjectIdentifier({ name: (names.keyAttrId || "") }),
|
||||
new asn1js.Any({
|
||||
optional: true,
|
||||
name: (names.keyAttr || "")
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"keyAttrId",
|
||||
"keyAttr"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
OtherKeyAttribute.schema({
|
||||
names: {
|
||||
keyAttrId: "keyAttrId",
|
||||
keyAttr: "keyAttr"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for OtherKeyAttribute");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.keyAttrId = asn1.result.keyAttrId.valueBlock.toString();
|
||||
|
||||
if("keyAttr" in asn1.result)
|
||||
this.keyAttr = asn1.result.keyAttr;
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Create array for output sequence
|
||||
const outputArray = [];
|
||||
|
||||
outputArray.push(new asn1js.ObjectIdentifier({ value: this.keyAttrId }));
|
||||
|
||||
if("keyAttr" in this)
|
||||
outputArray.push(this.keyAttr);
|
||||
//endregion
|
||||
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: outputArray
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
const _object = {
|
||||
keyAttrId: this.keyAttrId
|
||||
};
|
||||
|
||||
if("keyAttr" in this)
|
||||
_object.keyAttr = this.keyAttr.toJSON();
|
||||
|
||||
return _object;
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
190
core/third-party/pkijs/OtherPrimeInfo.js
vendored
Normal file
190
core/third-party/pkijs/OtherPrimeInfo.js
vendored
Normal file
@@ -0,0 +1,190 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, toBase64, arrayBufferToString, stringToArrayBuffer, fromBase64, clearProps } from "./pvutils.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC3447
|
||||
*/
|
||||
export default class OtherPrimeInfo
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for OtherPrimeInfo class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {Integer}
|
||||
* @desc prime
|
||||
*/
|
||||
this.prime = getParametersValue(parameters, "prime", OtherPrimeInfo.defaultValues("prime"));
|
||||
/**
|
||||
* @type {Integer}
|
||||
* @desc exponent
|
||||
*/
|
||||
this.exponent = getParametersValue(parameters, "exponent", OtherPrimeInfo.defaultValues("exponent"));
|
||||
/**
|
||||
* @type {Integer}
|
||||
* @desc coefficient
|
||||
*/
|
||||
this.coefficient = getParametersValue(parameters, "coefficient", OtherPrimeInfo.defaultValues("coefficient"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
//region If input argument array contains "json" for this object
|
||||
if("json" in parameters)
|
||||
this.fromJSON(parameters.json);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "prime":
|
||||
return new asn1js.Integer();
|
||||
case "exponent":
|
||||
return new asn1js.Integer();
|
||||
case "coefficient":
|
||||
return new asn1js.Integer();
|
||||
default:
|
||||
throw new Error(`Invalid member name for OtherPrimeInfo class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* OtherPrimeInfo ::= Sequence {
|
||||
* prime Integer, -- ri
|
||||
* exponent Integer, -- di
|
||||
* coefficient Integer -- ti
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} prime
|
||||
* @property {string} exponent
|
||||
* @property {string} coefficient
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.Integer({ name: (names.prime || "") }),
|
||||
new asn1js.Integer({ name: (names.exponent || "") }),
|
||||
new asn1js.Integer({ name: (names.coefficient || "") })
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"prime",
|
||||
"exponent",
|
||||
"coefficient"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
OtherPrimeInfo.schema({
|
||||
names: {
|
||||
prime: "prime",
|
||||
exponent: "exponent",
|
||||
coefficient: "coefficient"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for OtherPrimeInfo");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.prime = asn1.result.prime.convertFromDER();
|
||||
this.exponent = asn1.result.exponent.convertFromDER();
|
||||
this.coefficient = asn1.result.coefficient.convertFromDER();
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: [
|
||||
this.prime.convertToDER(),
|
||||
this.exponent.convertToDER(),
|
||||
this.coefficient.convertToDER()
|
||||
]
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
return {
|
||||
r: toBase64(arrayBufferToString(this.prime.valueBlock.valueHex), true, true),
|
||||
d: toBase64(arrayBufferToString(this.exponent.valueBlock.valueHex), true, true),
|
||||
t: toBase64(arrayBufferToString(this.coefficient.valueBlock.valueHex), true, true)
|
||||
};
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert JSON value into current object
|
||||
* @param {Object} json
|
||||
*/
|
||||
fromJSON(json)
|
||||
{
|
||||
if("r" in json)
|
||||
this.prime = new asn1js.Integer({ valueHex: stringToArrayBuffer(fromBase64(json.r, true)) });
|
||||
else
|
||||
throw new Error("Absent mandatory parameter \"r\"");
|
||||
|
||||
if("d" in json)
|
||||
this.exponent = new asn1js.Integer({ valueHex: stringToArrayBuffer(fromBase64(json.d, true)) });
|
||||
else
|
||||
throw new Error("Absent mandatory parameter \"d\"");
|
||||
|
||||
if("t" in json)
|
||||
this.coefficient = new asn1js.Integer({ valueHex: stringToArrayBuffer(fromBase64(json.t, true)) });
|
||||
else
|
||||
throw new Error("Absent mandatory parameter \"t\"");
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
170
core/third-party/pkijs/OtherRecipientInfo.js
vendored
Normal file
170
core/third-party/pkijs/OtherRecipientInfo.js
vendored
Normal file
@@ -0,0 +1,170 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5652
|
||||
*/
|
||||
export default class OtherRecipientInfo
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for OtherRecipientInfo class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {string}
|
||||
* @desc oriType
|
||||
*/
|
||||
this.oriType = getParametersValue(parameters, "oriType", OtherRecipientInfo.defaultValues("oriType"));
|
||||
/**
|
||||
* @type {*}
|
||||
* @desc oriValue
|
||||
*/
|
||||
this.oriValue = getParametersValue(parameters, "oriValue", OtherRecipientInfo.defaultValues("oriValue"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "oriType":
|
||||
return "";
|
||||
case "oriValue":
|
||||
return {};
|
||||
default:
|
||||
throw new Error(`Invalid member name for OtherRecipientInfo class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Compare values with default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
* @param {*} memberValue Value to compare with default value
|
||||
*/
|
||||
static compareWithDefault(memberName, memberValue)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "oriType":
|
||||
return (memberValue === "");
|
||||
case "oriValue":
|
||||
return (Object.keys(memberValue).length === 0);
|
||||
default:
|
||||
throw new Error(`Invalid member name for OtherRecipientInfo class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* OtherRecipientInfo ::= SEQUENCE {
|
||||
* oriType OBJECT IDENTIFIER,
|
||||
* oriValue ANY DEFINED BY oriType }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [oriType]
|
||||
* @property {string} [oriValue]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.ObjectIdentifier({ name: (names.oriType || "") }),
|
||||
new asn1js.Any({ name: (names.oriValue || "") })
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"oriType",
|
||||
"oriValue"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
OtherRecipientInfo.schema({
|
||||
names: {
|
||||
oriType: "oriType",
|
||||
oriValue: "oriValue"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for OtherRecipientInfo");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.oriType = asn1.result.oriType.valueBlock.toString();
|
||||
this.oriValue = asn1.result.oriValue;
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: [
|
||||
new asn1js.ObjectIdentifier({ value: this.oriType }),
|
||||
this.oriValue
|
||||
]
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
const _object = {
|
||||
oriType: this.oriType
|
||||
};
|
||||
|
||||
if(OtherRecipientInfo.compareWithDefault("oriValue", this.oriValue) === false)
|
||||
_object.oriValue = this.oriValue.toJSON();
|
||||
|
||||
return _object;
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
147
core/third-party/pkijs/OtherRevocationInfoFormat.js
vendored
Normal file
147
core/third-party/pkijs/OtherRevocationInfoFormat.js
vendored
Normal file
@@ -0,0 +1,147 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5652
|
||||
*/
|
||||
export default class OtherRevocationInfoFormat
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for OtherRevocationInfoFormat class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {string}
|
||||
* @desc otherRevInfoFormat
|
||||
*/
|
||||
this.otherRevInfoFormat = getParametersValue(parameters, "otherRevInfoFormat", OtherRevocationInfoFormat.defaultValues("otherRevInfoFormat"));
|
||||
/**
|
||||
* @type {Any}
|
||||
* @desc otherRevInfo
|
||||
*/
|
||||
this.otherRevInfo = getParametersValue(parameters, "otherRevInfo", OtherRevocationInfoFormat.defaultValues("otherRevInfo"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "otherRevInfoFormat":
|
||||
return "";
|
||||
case "otherRevInfo":
|
||||
return new asn1js.Any();
|
||||
default:
|
||||
throw new Error(`Invalid member name for OtherRevocationInfoFormat class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* OtherCertificateFormat ::= SEQUENCE {
|
||||
* otherRevInfoFormat OBJECT IDENTIFIER,
|
||||
* otherRevInfo ANY DEFINED BY otherCertFormat }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [otherRevInfoFormat]
|
||||
* @property {string} [otherRevInfo]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.ObjectIdentifier({ name: (names.otherRevInfoFormat || "otherRevInfoFormat") }),
|
||||
new asn1js.Any({ name: (names.otherRevInfo || "otherRevInfo") })
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"otherRevInfoFormat",
|
||||
"otherRevInfo"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
OtherRevocationInfoFormat.schema()
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for OtherRevocationInfoFormat");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.otherRevInfoFormat = asn1.result.otherRevInfoFormat.valueBlock.toString();
|
||||
this.otherRevInfo = asn1.result.otherRevInfo;
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: [
|
||||
new asn1js.ObjectIdentifier({ value: this.otherRevInfoFormat }),
|
||||
this.otherRevInfo
|
||||
]
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
const object = {
|
||||
otherRevInfoFormat: this.otherRevInfoFormat
|
||||
};
|
||||
|
||||
if(!(this.otherRevInfo instanceof asn1js.Any))
|
||||
object.otherRevInfo = this.otherRevInfo.toJSON();
|
||||
|
||||
return object;
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
157
core/third-party/pkijs/PBES2Params.js
vendored
Normal file
157
core/third-party/pkijs/PBES2Params.js
vendored
Normal file
@@ -0,0 +1,157 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import AlgorithmIdentifier from "./AlgorithmIdentifier.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC2898
|
||||
*/
|
||||
export default class PBES2Params
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for PBES2Params class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {AlgorithmIdentifier}
|
||||
* @desc keyDerivationFunc
|
||||
*/
|
||||
this.keyDerivationFunc = getParametersValue(parameters, "keyDerivationFunc", PBES2Params.defaultValues("keyDerivationFunc"));
|
||||
/**
|
||||
* @type {AlgorithmIdentifier}
|
||||
* @desc encryptionScheme
|
||||
*/
|
||||
this.encryptionScheme = getParametersValue(parameters, "encryptionScheme", PBES2Params.defaultValues("encryptionScheme"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "keyDerivationFunc":
|
||||
return new AlgorithmIdentifier();
|
||||
case "encryptionScheme":
|
||||
return new AlgorithmIdentifier();
|
||||
default:
|
||||
throw new Error(`Invalid member name for PBES2Params class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* PBES2-params ::= SEQUENCE {
|
||||
* keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
|
||||
* encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [keyDerivationFunc]
|
||||
* @property {string} [encryptionScheme]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
AlgorithmIdentifier.schema(names.keyDerivationFunc || {}),
|
||||
AlgorithmIdentifier.schema(names.encryptionScheme || {})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"keyDerivationFunc",
|
||||
"encryptionScheme"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
PBES2Params.schema({
|
||||
names: {
|
||||
keyDerivationFunc: {
|
||||
names: {
|
||||
blockName: "keyDerivationFunc"
|
||||
}
|
||||
},
|
||||
encryptionScheme: {
|
||||
names: {
|
||||
blockName: "encryptionScheme"
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for PBES2Params");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.keyDerivationFunc = new AlgorithmIdentifier({ schema: asn1.result.keyDerivationFunc });
|
||||
this.encryptionScheme = new AlgorithmIdentifier({ schema: asn1.result.encryptionScheme });
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: [
|
||||
this.keyDerivationFunc.toSchema(),
|
||||
this.encryptionScheme.toSchema()
|
||||
]
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
return {
|
||||
keyDerivationFunc: this.keyDerivationFunc.toJSON(),
|
||||
encryptionScheme: this.encryptionScheme.toJSON()
|
||||
};
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
242
core/third-party/pkijs/PBKDF2Params.js
vendored
Normal file
242
core/third-party/pkijs/PBKDF2Params.js
vendored
Normal file
@@ -0,0 +1,242 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import AlgorithmIdentifier from "./AlgorithmIdentifier.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC2898
|
||||
*/
|
||||
export default class PBKDF2Params
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for PBKDF2Params class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {Object}
|
||||
* @desc salt
|
||||
*/
|
||||
this.salt = getParametersValue(parameters, "salt", PBKDF2Params.defaultValues("salt"));
|
||||
/**
|
||||
* @type {number}
|
||||
* @desc iterationCount
|
||||
*/
|
||||
this.iterationCount = getParametersValue(parameters, "iterationCount", PBKDF2Params.defaultValues("iterationCount"));
|
||||
|
||||
if("keyLength" in parameters)
|
||||
/**
|
||||
* @type {number}
|
||||
* @desc keyLength
|
||||
*/
|
||||
this.keyLength = getParametersValue(parameters, "keyLength", PBKDF2Params.defaultValues("keyLength"));
|
||||
|
||||
if("prf" in parameters)
|
||||
/**
|
||||
* @type {AlgorithmIdentifier}
|
||||
* @desc prf
|
||||
*/
|
||||
this.prf = getParametersValue(parameters, "prf", PBKDF2Params.defaultValues("prf"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "salt":
|
||||
return {};
|
||||
case "iterationCount":
|
||||
return (-1);
|
||||
case "keyLength":
|
||||
return 0;
|
||||
case "prf":
|
||||
return new AlgorithmIdentifier({
|
||||
algorithmId: "1.3.14.3.2.26", // SHA-1
|
||||
algorithmParams: new asn1js.Null()
|
||||
});
|
||||
default:
|
||||
throw new Error(`Invalid member name for PBKDF2Params class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* PBKDF2-params ::= SEQUENCE {
|
||||
* salt CHOICE {
|
||||
* specified OCTET STRING,
|
||||
* otherSource AlgorithmIdentifier },
|
||||
* iterationCount INTEGER (1..MAX),
|
||||
* keyLength INTEGER (1..MAX) OPTIONAL,
|
||||
* prf AlgorithmIdentifier
|
||||
* DEFAULT { algorithm hMAC-SHA1, parameters NULL } }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [saltPrimitive]
|
||||
* @property {string} [saltConstructed]
|
||||
* @property {string} [iterationCount]
|
||||
* @property {string} [keyLength]
|
||||
* @property {string} [prf]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.Choice({
|
||||
value: [
|
||||
new asn1js.OctetString({ name: (names.saltPrimitive || "") }),
|
||||
AlgorithmIdentifier.schema(names.saltConstructed || {})
|
||||
]
|
||||
}),
|
||||
new asn1js.Integer({ name: (names.iterationCount || "") }),
|
||||
new asn1js.Integer({
|
||||
name: (names.keyLength || ""),
|
||||
optional: true
|
||||
}),
|
||||
AlgorithmIdentifier.schema(names.prf || {
|
||||
names: {
|
||||
optional: true
|
||||
}
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"salt",
|
||||
"iterationCount",
|
||||
"keyLength",
|
||||
"prf"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
PBKDF2Params.schema({
|
||||
names: {
|
||||
saltPrimitive: "salt",
|
||||
saltConstructed: {
|
||||
names: {
|
||||
blockName: "salt"
|
||||
}
|
||||
},
|
||||
iterationCount: "iterationCount",
|
||||
keyLength: "keyLength",
|
||||
prf: {
|
||||
names: {
|
||||
blockName: "prf",
|
||||
optional: true
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for PBKDF2Params");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.salt = asn1.result.salt;
|
||||
this.iterationCount = asn1.result.iterationCount.valueBlock.valueDec;
|
||||
|
||||
if("keyLength" in asn1.result)
|
||||
this.keyLength = asn1.result.keyLength.valueBlock.valueDec;
|
||||
|
||||
if("prf" in asn1.result)
|
||||
this.prf = new AlgorithmIdentifier({ schema: asn1.result.prf });
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Create array for output sequence
|
||||
const outputArray = [];
|
||||
|
||||
outputArray.push(this.salt);
|
||||
outputArray.push(new asn1js.Integer({ value: this.iterationCount }));
|
||||
|
||||
if("keyLength" in this)
|
||||
{
|
||||
if(PBKDF2Params.defaultValues("keyLength") !== this.keyLength)
|
||||
outputArray.push(new asn1js.Integer({ value: this.keyLength }));
|
||||
}
|
||||
|
||||
if("prf" in this)
|
||||
{
|
||||
if(PBKDF2Params.defaultValues("prf").isEqual(this.prf) === false)
|
||||
outputArray.push(this.prf.toSchema());
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: outputArray
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
const _object = {
|
||||
salt: this.salt.toJSON(),
|
||||
iterationCount: this.iterationCount
|
||||
};
|
||||
|
||||
if("keyLength" in this)
|
||||
{
|
||||
if(PBKDF2Params.defaultValues("keyLength") !== this.keyLength)
|
||||
_object.keyLength = this.keyLength;
|
||||
}
|
||||
|
||||
if("prf" in this)
|
||||
{
|
||||
if(PBKDF2Params.defaultValues("prf").isEqual(this.prf) === false)
|
||||
_object.prf = this.prf.toJSON();
|
||||
}
|
||||
|
||||
return _object;
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
650
core/third-party/pkijs/PFX.js
vendored
Normal file
650
core/third-party/pkijs/PFX.js
vendored
Normal file
@@ -0,0 +1,650 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, utilConcatBuf, clearProps } from "./pvutils.js";
|
||||
import { getCrypto, getEngine, getRandomValues, getOIDByAlgorithm, getAlgorithmByOID } from "./common.js";
|
||||
import ContentInfo from "./ContentInfo.js";
|
||||
import MacData from "./MacData.js";
|
||||
import DigestInfo from "./DigestInfo.js";
|
||||
import AlgorithmIdentifier from "./AlgorithmIdentifier.js";
|
||||
import SignedData from "./SignedData.js";
|
||||
import EncapsulatedContentInfo from "./EncapsulatedContentInfo.js";
|
||||
import Attribute from "./Attribute.js";
|
||||
import SignerInfo from "./SignerInfo.js";
|
||||
import IssuerAndSerialNumber from "./IssuerAndSerialNumber.js";
|
||||
import SignedAndUnsignedAttributes from "./SignedAndUnsignedAttributes.js";
|
||||
import AuthenticatedSafe from "./AuthenticatedSafe.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC7292
|
||||
*/
|
||||
export default class PFX
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for PFX class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {number}
|
||||
* @desc version
|
||||
*/
|
||||
this.version = getParametersValue(parameters, "version", PFX.defaultValues("version"));
|
||||
/**
|
||||
* @type {ContentInfo}
|
||||
* @desc authSafe
|
||||
*/
|
||||
this.authSafe = getParametersValue(parameters, "authSafe", PFX.defaultValues("authSafe"));
|
||||
|
||||
if("macData" in parameters)
|
||||
/**
|
||||
* @type {MacData}
|
||||
* @desc macData
|
||||
*/
|
||||
this.macData = getParametersValue(parameters, "macData", PFX.defaultValues("macData"));
|
||||
|
||||
if("parsedValue" in parameters)
|
||||
/**
|
||||
* @type {*}
|
||||
* @desc parsedValue
|
||||
*/
|
||||
this.parsedValue = getParametersValue(parameters, "parsedValue", PFX.defaultValues("parsedValue"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "version":
|
||||
return 3;
|
||||
case "authSafe":
|
||||
return (new ContentInfo());
|
||||
case "macData":
|
||||
return (new MacData());
|
||||
case "parsedValue":
|
||||
return {};
|
||||
default:
|
||||
throw new Error(`Invalid member name for PFX class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Compare values with default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
* @param {*} memberValue Value to compare with default value
|
||||
*/
|
||||
static compareWithDefault(memberName, memberValue)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "version":
|
||||
return (memberValue === PFX.defaultValues(memberName));
|
||||
case "authSafe":
|
||||
return ((ContentInfo.compareWithDefault("contentType", memberValue.contentType)) &&
|
||||
(ContentInfo.compareWithDefault("content", memberValue.content)));
|
||||
case "macData":
|
||||
return ((MacData.compareWithDefault("mac", memberValue.mac)) &&
|
||||
(MacData.compareWithDefault("macSalt", memberValue.macSalt)) &&
|
||||
(MacData.compareWithDefault("iterations", memberValue.iterations)));
|
||||
case "parsedValue":
|
||||
return ((memberValue instanceof Object) && (Object.keys(memberValue).length === 0));
|
||||
default:
|
||||
throw new Error(`Invalid member name for PFX class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* PFX ::= SEQUENCE {
|
||||
* version INTEGER {v3(3)}(v3,...),
|
||||
* authSafe ContentInfo,
|
||||
* macData MacData OPTIONAL
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [version]
|
||||
* @property {string} [authSafe]
|
||||
* @property {string} [macData]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.Integer({ name: (names.version || "version") }),
|
||||
ContentInfo.schema(names.authSafe || {
|
||||
names: {
|
||||
blockName: "authSafe"
|
||||
}
|
||||
}),
|
||||
MacData.schema(names.macData || {
|
||||
names: {
|
||||
blockName: "macData",
|
||||
optional: true
|
||||
}
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"version",
|
||||
"authSafe",
|
||||
"macData"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
PFX.schema({
|
||||
names: {
|
||||
version: "version",
|
||||
authSafe: {
|
||||
names: {
|
||||
blockName: "authSafe"
|
||||
}
|
||||
},
|
||||
macData: {
|
||||
names: {
|
||||
blockName: "macData"
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for PFX");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.version = asn1.result.version.valueBlock.valueDec;
|
||||
this.authSafe = new ContentInfo({ schema: asn1.result.authSafe });
|
||||
|
||||
if("macData" in asn1.result)
|
||||
this.macData = new MacData({ schema: asn1.result.macData });
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
const outputArray = [
|
||||
new asn1js.Integer({ value: this.version }),
|
||||
this.authSafe.toSchema()
|
||||
];
|
||||
|
||||
if("macData" in this)
|
||||
outputArray.push(this.macData.toSchema());
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
value: outputArray
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
const output = {
|
||||
version: this.version,
|
||||
authSafe: this.authSafe.toJSON()
|
||||
};
|
||||
|
||||
if("macData" in this)
|
||||
output.macData = this.macData.toJSON();
|
||||
|
||||
return output;
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Making ContentInfo from "parsedValue" object
|
||||
* @param {Object} parameters Parameters, specific to each "integrity mode"
|
||||
*/
|
||||
makeInternalValues(parameters = {})
|
||||
{
|
||||
//region Check mandatory parameter
|
||||
if((parameters instanceof Object) === false)
|
||||
return Promise.reject("The \"parameters\" must has \"Object\" type");
|
||||
|
||||
if(("parsedValue" in this) === false)
|
||||
return Promise.reject("Please call \"parseValues\" function first in order to make \"parsedValue\" data");
|
||||
|
||||
if(("integrityMode" in this.parsedValue) === false)
|
||||
return Promise.reject("Absent mandatory parameter \"integrityMode\" inside \"parsedValue\"");
|
||||
//endregion
|
||||
|
||||
//region Initial variables
|
||||
let sequence = Promise.resolve();
|
||||
//endregion
|
||||
|
||||
//region Get a "crypto" extension
|
||||
const crypto = getCrypto();
|
||||
if(typeof crypto === "undefined")
|
||||
return Promise.reject("Unable to create WebCrypto object");
|
||||
//endregion
|
||||
|
||||
//region Makes values for each particular integrity mode
|
||||
//region Check that we do have neccessary fields in "parsedValue" object
|
||||
if(("authenticatedSafe" in this.parsedValue) === false)
|
||||
return Promise.reject("Absent mandatory parameter \"authenticatedSafe\" in \"parsedValue\"");
|
||||
//endregion
|
||||
|
||||
switch(this.parsedValue.integrityMode)
|
||||
{
|
||||
//region HMAC-based integrity
|
||||
case 0:
|
||||
{
|
||||
//region Check additional mandatory parameters
|
||||
if(("iterations" in parameters) === false)
|
||||
return Promise.reject("Absent mandatory parameter \"iterations\"");
|
||||
|
||||
if(("pbkdf2HashAlgorithm" in parameters) === false)
|
||||
return Promise.reject("Absent mandatory parameter \"pbkdf2HashAlgorithm\"");
|
||||
|
||||
if(("hmacHashAlgorithm" in parameters) === false)
|
||||
return Promise.reject("Absent mandatory parameter \"hmacHashAlgorithm\"");
|
||||
|
||||
if(("password" in parameters) === false)
|
||||
return Promise.reject("Absent mandatory parameter \"password\"");
|
||||
//endregion
|
||||
|
||||
//region Initial variables
|
||||
const saltBuffer = new ArrayBuffer(64);
|
||||
const saltView = new Uint8Array(saltBuffer);
|
||||
|
||||
getRandomValues(saltView);
|
||||
|
||||
const data = this.parsedValue.authenticatedSafe.toSchema().toBER(false);
|
||||
|
||||
this.authSafe = new ContentInfo({
|
||||
contentType: "1.2.840.113549.1.7.1",
|
||||
content: new asn1js.OctetString({ valueHex: data })
|
||||
});
|
||||
//endregion
|
||||
|
||||
//region Call current crypto engine for making HMAC-based data stamp
|
||||
const engine = getEngine();
|
||||
|
||||
if(("stampDataWithPassword" in engine.subtle) === false)
|
||||
return Promise.reject(`No support for "stampDataWithPassword" in current engine "${engine.name}"`);
|
||||
|
||||
sequence = sequence.then(() =>
|
||||
engine.subtle.stampDataWithPassword({
|
||||
password: parameters.password,
|
||||
hashAlgorithm: parameters.hmacHashAlgorithm,
|
||||
salt: saltBuffer,
|
||||
iterationCount: parameters.iterations,
|
||||
contentToStamp: data
|
||||
})
|
||||
);
|
||||
//endregion
|
||||
|
||||
//region Make "MacData" values
|
||||
sequence = sequence.then(
|
||||
result =>
|
||||
{
|
||||
this.macData = new MacData({
|
||||
mac: new DigestInfo({
|
||||
digestAlgorithm: new AlgorithmIdentifier({
|
||||
algorithmId: getOIDByAlgorithm({ name: parameters.hmacHashAlgorithm })
|
||||
}),
|
||||
digest: new asn1js.OctetString({ valueHex: result })
|
||||
}),
|
||||
macSalt: new asn1js.OctetString({ valueHex: saltBuffer }),
|
||||
iterations: parameters.iterations
|
||||
});
|
||||
},
|
||||
error => Promise.reject(error)
|
||||
);
|
||||
//endregion
|
||||
//endregion
|
||||
}
|
||||
break;
|
||||
//endregion
|
||||
//region publicKey-based integrity
|
||||
case 1:
|
||||
{
|
||||
//region Check additional mandatory parameters
|
||||
if(("signingCertificate" in parameters) === false)
|
||||
return Promise.reject("Absent mandatory parameter \"signingCertificate\"");
|
||||
|
||||
if(("privateKey" in parameters) === false)
|
||||
return Promise.reject("Absent mandatory parameter \"privateKey\"");
|
||||
|
||||
if(("hashAlgorithm" in parameters) === false)
|
||||
return Promise.reject("Absent mandatory parameter \"hashAlgorithm\"");
|
||||
//endregion
|
||||
|
||||
//region Making data to be signed
|
||||
// NOTE: all internal data for "authenticatedSafe" must be already prepared.
|
||||
// Thus user must call "makeValues" for all internal "SafeContent" value with appropriate parameters.
|
||||
// Or user can choose to use values from initial parsing of existing PKCS#12 data.
|
||||
|
||||
const toBeSigned = this.parsedValue.authenticatedSafe.toSchema().toBER(false);
|
||||
//endregion
|
||||
|
||||
//region Initial variables
|
||||
const cmsSigned = new SignedData({
|
||||
version: 1,
|
||||
encapContentInfo: new EncapsulatedContentInfo({
|
||||
eContentType: "1.2.840.113549.1.7.1", // "data" content type
|
||||
eContent: new asn1js.OctetString({ valueHex: toBeSigned })
|
||||
}),
|
||||
certificates: [parameters.signingCertificate]
|
||||
});
|
||||
//endregion
|
||||
|
||||
//region Making additional attributes for CMS Signed Data
|
||||
//region Create a message digest
|
||||
sequence = sequence.then(
|
||||
() => crypto.digest({ name: parameters.hashAlgorithm }, new Uint8Array(toBeSigned))
|
||||
);
|
||||
//endregion
|
||||
|
||||
//region Combine all signed extensions
|
||||
sequence = sequence.then(
|
||||
result =>
|
||||
{
|
||||
//region Initial variables
|
||||
const signedAttr = [];
|
||||
//endregion
|
||||
|
||||
//region contentType
|
||||
signedAttr.push(new Attribute({
|
||||
type: "1.2.840.113549.1.9.3",
|
||||
values: [
|
||||
new asn1js.ObjectIdentifier({ value: "1.2.840.113549.1.7.1" })
|
||||
]
|
||||
}));
|
||||
//endregion
|
||||
//region signingTime
|
||||
signedAttr.push(new Attribute({
|
||||
type: "1.2.840.113549.1.9.5",
|
||||
values: [
|
||||
new asn1js.UTCTime({ valueDate: new Date() })
|
||||
]
|
||||
}));
|
||||
//endregion
|
||||
//region messageDigest
|
||||
signedAttr.push(new Attribute({
|
||||
type: "1.2.840.113549.1.9.4",
|
||||
values: [
|
||||
new asn1js.OctetString({ valueHex: result })
|
||||
]
|
||||
}));
|
||||
//endregion
|
||||
|
||||
//region Making final value for "SignerInfo" type
|
||||
cmsSigned.signerInfos.push(new SignerInfo({
|
||||
version: 1,
|
||||
sid: new IssuerAndSerialNumber({
|
||||
issuer: parameters.signingCertificate.issuer,
|
||||
serialNumber: parameters.signingCertificate.serialNumber
|
||||
}),
|
||||
signedAttrs: new SignedAndUnsignedAttributes({
|
||||
type: 0,
|
||||
attributes: signedAttr
|
||||
})
|
||||
}));
|
||||
//endregion
|
||||
},
|
||||
error => Promise.reject(`Error during making digest for message: ${error}`)
|
||||
);
|
||||
//endregion
|
||||
//endregion
|
||||
|
||||
//region Signing CMS Signed Data
|
||||
sequence = sequence.then(
|
||||
() => cmsSigned.sign(parameters.privateKey, 0, parameters.hashAlgorithm)
|
||||
);
|
||||
//endregion
|
||||
|
||||
//region Making final CMS_CONTENT_INFO type
|
||||
sequence = sequence.then(
|
||||
() =>
|
||||
{
|
||||
this.authSafe = new ContentInfo({
|
||||
contentType: "1.2.840.113549.1.7.2",
|
||||
content: cmsSigned.toSchema(true)
|
||||
});
|
||||
},
|
||||
error => Promise.reject(`Error during making signature: ${error}`)
|
||||
);
|
||||
//endregion
|
||||
}
|
||||
break;
|
||||
//endregion
|
||||
//region default
|
||||
default:
|
||||
return Promise.reject(`Parameter "integrityMode" has unknown value: ${parameters.integrityMode}`);
|
||||
//endregion
|
||||
}
|
||||
//endregion
|
||||
|
||||
return sequence;
|
||||
}
|
||||
//**********************************************************************************
|
||||
parseInternalValues(parameters)
|
||||
{
|
||||
//region Check input data from "parameters"
|
||||
if((parameters instanceof Object) === false)
|
||||
return Promise.reject("The \"parameters\" must has \"Object\" type");
|
||||
|
||||
if(("checkIntegrity" in parameters) === false)
|
||||
parameters.checkIntegrity = true;
|
||||
//endregion
|
||||
|
||||
//region Initial variables
|
||||
let sequence = Promise.resolve();
|
||||
//endregion
|
||||
|
||||
//region Get a "crypto" extension
|
||||
const crypto = getCrypto();
|
||||
if(typeof crypto === "undefined")
|
||||
return Promise.reject("Unable to create WebCrypto object");
|
||||
//endregion
|
||||
|
||||
//region Create value for "this.parsedValue.authenticatedSafe" and check integrity
|
||||
this.parsedValue = {};
|
||||
|
||||
switch(this.authSafe.contentType)
|
||||
{
|
||||
//region data
|
||||
case "1.2.840.113549.1.7.1":
|
||||
{
|
||||
//region Check additional mandatory parameters
|
||||
if(("password" in parameters) === false)
|
||||
return Promise.reject("Absent mandatory parameter \"password\"");
|
||||
//endregion
|
||||
|
||||
//region Integrity based on HMAC
|
||||
this.parsedValue.integrityMode = 0;
|
||||
//endregion
|
||||
|
||||
//region Check that we do have OCTETSTRING as "content"
|
||||
if((this.authSafe.content instanceof asn1js.OctetString) === false)
|
||||
return Promise.reject("Wrong type of \"this.authSafe.content\"");
|
||||
//endregion
|
||||
|
||||
//region Check we have "constructive encoding" for AuthSafe content
|
||||
let authSafeContent = new ArrayBuffer(0);
|
||||
|
||||
if(this.authSafe.content.valueBlock.isConstructed)
|
||||
{
|
||||
for(const contentValue of this.authSafe.content.valueBlock.value)
|
||||
authSafeContent = utilConcatBuf(authSafeContent, contentValue.valueBlock.valueHex);
|
||||
}
|
||||
else
|
||||
authSafeContent = this.authSafe.content.valueBlock.valueHex;
|
||||
//endregion
|
||||
|
||||
//region Parse internal ASN.1 data
|
||||
const asn1 = asn1js.fromBER(authSafeContent);
|
||||
if(asn1.offset === (-1))
|
||||
return Promise.reject("Error during parsing of ASN.1 data inside \"this.authSafe.content\"");
|
||||
//endregion
|
||||
|
||||
//region Set "authenticatedSafe" value
|
||||
this.parsedValue.authenticatedSafe = new AuthenticatedSafe({ schema: asn1.result });
|
||||
//endregion
|
||||
|
||||
//region Check integrity
|
||||
if(parameters.checkIntegrity)
|
||||
{
|
||||
//region Check that "MacData" exists
|
||||
if(("macData" in this) === false)
|
||||
return Promise.reject("Absent \"macData\" value, can not check PKCS#12 data integrity");
|
||||
//endregion
|
||||
|
||||
//region Initial variables
|
||||
const hashAlgorithm = getAlgorithmByOID(this.macData.mac.digestAlgorithm.algorithmId);
|
||||
if(("name" in hashAlgorithm) === false)
|
||||
return Promise.reject(`Unsupported digest algorithm: ${this.macData.mac.digestAlgorithm.algorithmId}`);
|
||||
//endregion
|
||||
|
||||
//region Call current crypto engine for verifying HMAC-based data stamp
|
||||
const engine = getEngine();
|
||||
|
||||
sequence = sequence.then(() =>
|
||||
engine.subtle.verifyDataStampedWithPassword({
|
||||
password: parameters.password,
|
||||
hashAlgorithm: hashAlgorithm.name,
|
||||
salt: this.macData.macSalt.valueBlock.valueHex,
|
||||
iterationCount: this.macData.iterations,
|
||||
contentToVerify: authSafeContent,
|
||||
signatureToVerify: this.macData.mac.digest.valueBlock.valueHex
|
||||
})
|
||||
);
|
||||
//endregion
|
||||
|
||||
//region Verify HMAC signature
|
||||
sequence = sequence.then(
|
||||
result =>
|
||||
{
|
||||
if(result === false)
|
||||
return Promise.reject("Integrity for the PKCS#12 data is broken!");
|
||||
|
||||
return Promise.resolve();
|
||||
},
|
||||
error => Promise.reject(error)
|
||||
);
|
||||
//endregion
|
||||
}
|
||||
//endregion
|
||||
}
|
||||
break;
|
||||
//endregion
|
||||
//region signedData
|
||||
case "1.2.840.113549.1.7.2":
|
||||
{
|
||||
//region Integrity based on signature using public key
|
||||
this.parsedValue.integrityMode = 1;
|
||||
//endregion
|
||||
|
||||
//region Parse CMS Signed Data
|
||||
const cmsSigned = new SignedData({ schema: this.authSafe.content });
|
||||
//endregion
|
||||
|
||||
//region Check that we do have OCTETSTRING as "content"
|
||||
if(("eContent" in cmsSigned.encapContentInfo) === false)
|
||||
return Promise.reject("Absent of attached data in \"cmsSigned.encapContentInfo\"");
|
||||
|
||||
if((cmsSigned.encapContentInfo.eContent instanceof asn1js.OctetString) === false)
|
||||
return Promise.reject("Wrong type of \"cmsSigned.encapContentInfo.eContent\"");
|
||||
//endregion
|
||||
|
||||
//region Create correct data block for verification
|
||||
let data = new ArrayBuffer(0);
|
||||
|
||||
if(cmsSigned.encapContentInfo.eContent.idBlock.isConstructed === false)
|
||||
data = cmsSigned.encapContentInfo.eContent.valueBlock.valueHex;
|
||||
else
|
||||
{
|
||||
for(let i = 0; i < cmsSigned.encapContentInfo.eContent.valueBlock.value.length; i++)
|
||||
data = utilConcatBuf(data, cmsSigned.encapContentInfo.eContent.valueBlock.value[i].valueBlock.valueHex);
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region Parse internal ASN.1 data
|
||||
const asn1 = asn1js.fromBER(data);
|
||||
if(asn1.offset === (-1))
|
||||
return Promise.reject("Error during parsing of ASN.1 data inside \"this.authSafe.content\"");
|
||||
//endregion
|
||||
|
||||
//region Set "authenticatedSafe" value
|
||||
this.parsedValue.authenticatedSafe = new AuthenticatedSafe({ schema: asn1.result });
|
||||
//endregion
|
||||
|
||||
//region Check integrity
|
||||
sequence = sequence.then(
|
||||
() => cmsSigned.verify({ signer: 0, checkChain: false })
|
||||
).then(
|
||||
result =>
|
||||
{
|
||||
if(result === false)
|
||||
return Promise.reject("Integrity for the PKCS#12 data is broken!");
|
||||
|
||||
return Promise.resolve();
|
||||
},
|
||||
error => Promise.reject(`Error during integrity verification: ${error}`)
|
||||
);
|
||||
//endregion
|
||||
}
|
||||
break;
|
||||
//endregion
|
||||
//region default
|
||||
default:
|
||||
return Promise.reject(`Incorrect value for "this.authSafe.contentType": ${this.authSafe.contentType}`);
|
||||
//endregion
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region Return result of the function
|
||||
return sequence.then(
|
||||
() => this,
|
||||
error => Promise.reject(`Error during parsing: ${error}`)
|
||||
);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
285
core/third-party/pkijs/PKCS8ShroudedKeyBag.js
vendored
Normal file
285
core/third-party/pkijs/PKCS8ShroudedKeyBag.js
vendored
Normal file
@@ -0,0 +1,285 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import AlgorithmIdentifier from "./AlgorithmIdentifier.js";
|
||||
import EncryptedData from "./EncryptedData.js";
|
||||
import EncryptedContentInfo from "./EncryptedContentInfo.js";
|
||||
import PrivateKeyInfo from "./PrivateKeyInfo.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC7292
|
||||
*/
|
||||
export default class PKCS8ShroudedKeyBag
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for PKCS8ShroudedKeyBag class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {AlgorithmIdentifier}
|
||||
* @desc encryptionAlgorithm
|
||||
*/
|
||||
this.encryptionAlgorithm = getParametersValue(parameters, "encryptionAlgorithm", PKCS8ShroudedKeyBag.defaultValues("encryptionAlgorithm"));
|
||||
/**
|
||||
* @type {OctetString}
|
||||
* @desc encryptedData
|
||||
*/
|
||||
this.encryptedData = getParametersValue(parameters, "encryptedData", PKCS8ShroudedKeyBag.defaultValues("encryptedData"));
|
||||
|
||||
if("parsedValue" in parameters)
|
||||
/**
|
||||
* @type {*}
|
||||
* @desc parsedValue
|
||||
*/
|
||||
this.parsedValue = getParametersValue(parameters, "parsedValue", PKCS8ShroudedKeyBag.defaultValues("parsedValue"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "encryptionAlgorithm":
|
||||
return (new AlgorithmIdentifier());
|
||||
case "encryptedData":
|
||||
return (new asn1js.OctetString());
|
||||
case "parsedValue":
|
||||
return {};
|
||||
default:
|
||||
throw new Error(`Invalid member name for PKCS8ShroudedKeyBag class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Compare values with default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
* @param {*} memberValue Value to compare with default value
|
||||
*/
|
||||
static compareWithDefault(memberName, memberValue)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "encryptionAlgorithm":
|
||||
return ((AlgorithmIdentifier.compareWithDefault("algorithmId", memberValue.algorithmId)) &&
|
||||
(("algorithmParams" in memberValue) === false));
|
||||
case "encryptedData":
|
||||
return (memberValue.isEqual(PKCS8ShroudedKeyBag.defaultValues(memberName)));
|
||||
case "parsedValue":
|
||||
return ((memberValue instanceof Object) && (Object.keys(memberValue).length === 0));
|
||||
default:
|
||||
throw new Error(`Invalid member name for PKCS8ShroudedKeyBag class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* PKCS8ShroudedKeyBag ::= EncryptedPrivateKeyInfo
|
||||
*
|
||||
* EncryptedPrivateKeyInfo ::= SEQUENCE {
|
||||
* encryptionAlgorithm AlgorithmIdentifier {{KeyEncryptionAlgorithms}},
|
||||
* encryptedData EncryptedData
|
||||
* }
|
||||
*
|
||||
* EncryptedData ::= OCTET STRING
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [encryptionAlgorithm]
|
||||
* @property {string} [encryptedData]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
AlgorithmIdentifier.schema(names.encryptionAlgorithm || {
|
||||
names: {
|
||||
blockName: "encryptionAlgorithm"
|
||||
}
|
||||
}),
|
||||
new asn1js.Choice({
|
||||
value: [
|
||||
new asn1js.OctetString({ name: (names.encryptedData || "encryptedData") }),
|
||||
new asn1js.OctetString({
|
||||
idBlock: {
|
||||
isConstructed: true
|
||||
},
|
||||
name: (names.encryptedData || "encryptedData")
|
||||
})
|
||||
]
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"encryptionAlgorithm",
|
||||
"encryptedData"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
PKCS8ShroudedKeyBag.schema({
|
||||
names: {
|
||||
encryptionAlgorithm: {
|
||||
names: {
|
||||
blockName: "encryptionAlgorithm"
|
||||
}
|
||||
},
|
||||
encryptedData: "encryptedData"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for PKCS8ShroudedKeyBag");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.encryptionAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.encryptionAlgorithm });
|
||||
this.encryptedData = asn1.result.encryptedData;
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: [
|
||||
this.encryptionAlgorithm.toSchema(),
|
||||
this.encryptedData
|
||||
]
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
return {
|
||||
encryptionAlgorithm: this.encryptionAlgorithm.toJSON(),
|
||||
encryptedData: this.encryptedData.toJSON()
|
||||
};
|
||||
}
|
||||
//**********************************************************************************
|
||||
parseInternalValues(parameters)
|
||||
{
|
||||
//region Initial variables
|
||||
let sequence = Promise.resolve();
|
||||
|
||||
const cmsEncrypted = new EncryptedData({
|
||||
encryptedContentInfo: new EncryptedContentInfo({
|
||||
contentEncryptionAlgorithm: this.encryptionAlgorithm,
|
||||
encryptedContent: this.encryptedData
|
||||
})
|
||||
});
|
||||
//endregion
|
||||
|
||||
//region Decrypt internal data
|
||||
sequence = sequence.then(
|
||||
() => cmsEncrypted.decrypt(parameters),
|
||||
error => Promise.reject(error)
|
||||
);
|
||||
//endregion
|
||||
|
||||
//region Initialize "parsedValue" with decrypted PKCS#8 private key
|
||||
sequence = sequence.then(
|
||||
/**
|
||||
* @param {ArrayBuffer} result
|
||||
*/
|
||||
result =>
|
||||
{
|
||||
const asn1 = asn1js.fromBER(result);
|
||||
if(asn1.offset === (-1))
|
||||
return Promise.reject("Error during parsing ASN.1 data");
|
||||
|
||||
this.parsedValue = new PrivateKeyInfo({ schema: asn1.result });
|
||||
|
||||
return Promise.resolve();
|
||||
},
|
||||
error => Promise.reject(error)
|
||||
);
|
||||
//endregion
|
||||
|
||||
return sequence;
|
||||
}
|
||||
//**********************************************************************************
|
||||
makeInternalValues(parameters)
|
||||
{
|
||||
//region Check that we do have "parsedValue"
|
||||
if(("parsedValue" in this) === false)
|
||||
return Promise.reject("Please initialize \"parsedValue\" first");
|
||||
//endregion
|
||||
|
||||
//region Initial variables
|
||||
let sequence = Promise.resolve();
|
||||
|
||||
const cmsEncrypted = new EncryptedData();
|
||||
//endregion
|
||||
|
||||
//region Encrypt internal data
|
||||
sequence = sequence.then(
|
||||
() =>
|
||||
{
|
||||
parameters.contentToEncrypt = this.parsedValue.toSchema().toBER(false);
|
||||
|
||||
return cmsEncrypted.encrypt(parameters);
|
||||
},
|
||||
error => Promise.reject(error)
|
||||
);
|
||||
//endregion
|
||||
|
||||
//region Initialize internal values
|
||||
sequence = sequence.then(
|
||||
() =>
|
||||
{
|
||||
this.encryptionAlgorithm = cmsEncrypted.encryptedContentInfo.contentEncryptionAlgorithm;
|
||||
this.encryptedData = cmsEncrypted.encryptedContentInfo.encryptedContent;
|
||||
}
|
||||
);
|
||||
//endregion
|
||||
|
||||
return sequence;
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
227
core/third-party/pkijs/PKIStatusInfo.js
vendored
Normal file
227
core/third-party/pkijs/PKIStatusInfo.js
vendored
Normal file
@@ -0,0 +1,227 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC3161
|
||||
*/
|
||||
export default class PKIStatusInfo
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for PKIStatusInfo class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {number}
|
||||
* @desc status
|
||||
*/
|
||||
this.status = getParametersValue(parameters, "status", PKIStatusInfo.defaultValues("status"));
|
||||
|
||||
if("statusStrings" in parameters)
|
||||
/**
|
||||
* @type {Array.<Utf8String>}
|
||||
* @desc statusStrings
|
||||
*/
|
||||
this.statusStrings = getParametersValue(parameters, "statusStrings", PKIStatusInfo.defaultValues("statusStrings"));
|
||||
|
||||
if("failInfo" in parameters)
|
||||
/**
|
||||
* @type {BitString}
|
||||
* @desc failInfo
|
||||
*/
|
||||
this.failInfo = getParametersValue(parameters, "failInfo", PKIStatusInfo.defaultValues("failInfo"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "status":
|
||||
return 2;
|
||||
case "statusStrings":
|
||||
return [];
|
||||
case "failInfo":
|
||||
return new asn1js.BitString();
|
||||
default:
|
||||
throw new Error(`Invalid member name for PKIStatusInfo class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Compare values with default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
* @param {*} memberValue Value to compare with default value
|
||||
*/
|
||||
static compareWithDefault(memberName, memberValue)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "status":
|
||||
return (memberValue === PKIStatusInfo.defaultValues(memberName));
|
||||
case "statusStrings":
|
||||
return (memberValue.length === 0);
|
||||
case "failInfo":
|
||||
return (memberValue.isEqual(PKIStatusInfo.defaultValues(memberName)));
|
||||
default:
|
||||
throw new Error(`Invalid member name for PKIStatusInfo class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* PKIStatusInfo ::= SEQUENCE {
|
||||
* status PKIStatus,
|
||||
* statusString PKIFreeText OPTIONAL,
|
||||
* failInfo PKIFailureInfo OPTIONAL }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [status]
|
||||
* @property {string} [statusStrings]
|
||||
* @property {string} [failInfo]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.Integer({ name: (names.status || "") }),
|
||||
new asn1js.Sequence({
|
||||
optional: true,
|
||||
value: [
|
||||
new asn1js.Repeated({
|
||||
name: (names.statusStrings || ""),
|
||||
value: new asn1js.Utf8String()
|
||||
})
|
||||
]
|
||||
}),
|
||||
new asn1js.BitString({
|
||||
name: (names.failInfo || ""),
|
||||
optional: true
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"status",
|
||||
"statusStrings",
|
||||
"failInfo"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
PKIStatusInfo.schema({
|
||||
names: {
|
||||
status: "status",
|
||||
statusStrings: "statusStrings",
|
||||
failInfo: "failInfo"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for PKIStatusInfo");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
const _status = asn1.result.status;
|
||||
|
||||
if((_status.valueBlock.isHexOnly === true) ||
|
||||
(_status.valueBlock.valueDec < 0) ||
|
||||
(_status.valueBlock.valueDec > 5))
|
||||
throw new Error("PKIStatusInfo \"status\" has invalid value");
|
||||
|
||||
this.status = _status.valueBlock.valueDec;
|
||||
|
||||
if("statusStrings" in asn1.result)
|
||||
this.statusStrings = asn1.result.statusStrings;
|
||||
if("failInfo" in asn1.result)
|
||||
this.failInfo = asn1.result.failInfo;
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Create array of output sequence
|
||||
const outputArray = [];
|
||||
|
||||
outputArray.push(new asn1js.Integer({ value: this.status }));
|
||||
|
||||
if("statusStrings" in this)
|
||||
{
|
||||
outputArray.push(new asn1js.Sequence({
|
||||
optional: true,
|
||||
value: this.statusStrings
|
||||
}));
|
||||
}
|
||||
|
||||
if("failInfo" in this)
|
||||
outputArray.push(this.failInfo);
|
||||
//endregion
|
||||
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: outputArray
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
const _object = {
|
||||
status: this.status
|
||||
};
|
||||
|
||||
if("statusStrings" in this)
|
||||
_object.statusStrings = Array.from(this.statusStrings, element => element.toJSON());
|
||||
|
||||
if("failInfo" in this)
|
||||
_object.failInfo = this.failInfo.toJSON();
|
||||
|
||||
return _object;
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
247
core/third-party/pkijs/PasswordRecipientinfo.js
vendored
Normal file
247
core/third-party/pkijs/PasswordRecipientinfo.js
vendored
Normal file
@@ -0,0 +1,247 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import AlgorithmIdentifier from "./AlgorithmIdentifier.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5652
|
||||
*/
|
||||
export default class PasswordRecipientinfo
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for PasswordRecipientinfo class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {number}
|
||||
* @desc version
|
||||
*/
|
||||
this.version = getParametersValue(parameters, "version", PasswordRecipientinfo.defaultValues("version"));
|
||||
|
||||
if("keyDerivationAlgorithm" in parameters)
|
||||
/**
|
||||
* @type {AlgorithmIdentifier}
|
||||
* @desc keyDerivationAlgorithm
|
||||
*/
|
||||
this.keyDerivationAlgorithm = getParametersValue(parameters, "keyDerivationAlgorithm", PasswordRecipientinfo.defaultValues("keyDerivationAlgorithm"));
|
||||
|
||||
/**
|
||||
* @type {AlgorithmIdentifier}
|
||||
* @desc keyEncryptionAlgorithm
|
||||
*/
|
||||
this.keyEncryptionAlgorithm = getParametersValue(parameters, "keyEncryptionAlgorithm", PasswordRecipientinfo.defaultValues("keyEncryptionAlgorithm"));
|
||||
/**
|
||||
* @type {OctetString}
|
||||
* @desc encryptedKey
|
||||
*/
|
||||
this.encryptedKey = getParametersValue(parameters, "encryptedKey", PasswordRecipientinfo.defaultValues("encryptedKey"));
|
||||
/**
|
||||
* @type {ArrayBuffer}
|
||||
* @desc password Password to derive key from
|
||||
*/
|
||||
this.password = getParametersValue(parameters, "password", PasswordRecipientinfo.defaultValues("password"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "version":
|
||||
return (-1);
|
||||
case "keyDerivationAlgorithm":
|
||||
return new AlgorithmIdentifier();
|
||||
case "keyEncryptionAlgorithm":
|
||||
return new AlgorithmIdentifier();
|
||||
case "encryptedKey":
|
||||
return new asn1js.OctetString();
|
||||
case "password":
|
||||
return new ArrayBuffer(0);
|
||||
default:
|
||||
throw new Error(`Invalid member name for PasswordRecipientinfo class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Compare values with default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
* @param {*} memberValue Value to compare with default value
|
||||
*/
|
||||
static compareWithDefault(memberName, memberValue)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "version":
|
||||
return (memberValue === (-1));
|
||||
case "keyDerivationAlgorithm":
|
||||
case "keyEncryptionAlgorithm":
|
||||
return ((memberValue.algorithmId === "") && (("algorithmParams" in memberValue) === false));
|
||||
case "encryptedKey":
|
||||
return (memberValue.isEqual(PasswordRecipientinfo.defaultValues("encryptedKey")));
|
||||
case "password":
|
||||
return (memberValue.byteLength === 0);
|
||||
default:
|
||||
throw new Error(`Invalid member name for PasswordRecipientinfo class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* PasswordRecipientInfo ::= SEQUENCE {
|
||||
* version CMSVersion, -- Always set to 0
|
||||
* keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier OPTIONAL,
|
||||
* keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
|
||||
* encryptedKey EncryptedKey }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [keyDerivationAlgorithm]
|
||||
* @property {string} [keyEncryptionAlgorithm]
|
||||
* @property {string} [encryptedKey]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.Integer({ name: (names.version || "") }),
|
||||
new asn1js.Constructed({
|
||||
name: (names.keyDerivationAlgorithm || ""),
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: AlgorithmIdentifier.schema().valueBlock.value
|
||||
}),
|
||||
AlgorithmIdentifier.schema(names.keyEncryptionAlgorithm || {}),
|
||||
new asn1js.OctetString({ name: (names.encryptedKey || "") })
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"version",
|
||||
"keyDerivationAlgorithm",
|
||||
"keyEncryptionAlgorithm",
|
||||
"encryptedKey"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
PasswordRecipientinfo.schema({
|
||||
names: {
|
||||
version: "version",
|
||||
keyDerivationAlgorithm: "keyDerivationAlgorithm",
|
||||
keyEncryptionAlgorithm: {
|
||||
names: {
|
||||
blockName: "keyEncryptionAlgorithm"
|
||||
}
|
||||
},
|
||||
encryptedKey: "encryptedKey"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for PasswordRecipientinfo");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.version = asn1.result.version.valueBlock.valueDec;
|
||||
|
||||
if("keyDerivationAlgorithm" in asn1.result)
|
||||
{
|
||||
this.keyDerivationAlgorithm = new AlgorithmIdentifier({
|
||||
schema: new asn1js.Sequence({
|
||||
value: asn1.result.keyDerivationAlgorithm.valueBlock.value
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
this.keyEncryptionAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.keyEncryptionAlgorithm });
|
||||
this.encryptedKey = asn1.result.encryptedKey;
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Create output array for sequence
|
||||
const outputArray = [];
|
||||
|
||||
outputArray.push(new asn1js.Integer({ value: this.version }));
|
||||
|
||||
if("keyDerivationAlgorithm" in this)
|
||||
{
|
||||
outputArray.push(new asn1js.Constructed({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: this.keyDerivationAlgorithm.toSchema().valueBlock.value
|
||||
}));
|
||||
}
|
||||
|
||||
outputArray.push(this.keyEncryptionAlgorithm.toSchema());
|
||||
outputArray.push(this.encryptedKey);
|
||||
//endregion
|
||||
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: outputArray
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
return {
|
||||
version: this.version,
|
||||
keyDerivationAlgorithm: this.keyDerivationAlgorithm.toJSON(),
|
||||
keyEncryptionAlgorithm: this.keyEncryptionAlgorithm.toJSON(),
|
||||
encryptedKey: this.encryptedKey.toJSON()
|
||||
};
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
216
core/third-party/pkijs/PolicyConstraints.js
vendored
Normal file
216
core/third-party/pkijs/PolicyConstraints.js
vendored
Normal file
@@ -0,0 +1,216 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5280
|
||||
*/
|
||||
export default class PolicyConstraints
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for PolicyConstraints class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
if("requireExplicitPolicy" in parameters)
|
||||
/**
|
||||
* @type {number}
|
||||
* @desc requireExplicitPolicy
|
||||
*/
|
||||
this.requireExplicitPolicy = getParametersValue(parameters, "requireExplicitPolicy", PolicyConstraints.defaultValues("requireExplicitPolicy"));
|
||||
|
||||
if("inhibitPolicyMapping" in parameters)
|
||||
/**
|
||||
* @type {number}
|
||||
* @desc Value of the TIME class
|
||||
*/
|
||||
this.inhibitPolicyMapping = getParametersValue(parameters, "inhibitPolicyMapping", PolicyConstraints.defaultValues("inhibitPolicyMapping"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "requireExplicitPolicy":
|
||||
return 0;
|
||||
case "inhibitPolicyMapping":
|
||||
return 0;
|
||||
default:
|
||||
throw new Error(`Invalid member name for PolicyConstraints class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* PolicyConstraints ::= SEQUENCE {
|
||||
* requireExplicitPolicy [0] SkipCerts OPTIONAL,
|
||||
* inhibitPolicyMapping [1] SkipCerts OPTIONAL }
|
||||
*
|
||||
* SkipCerts ::= INTEGER (0..MAX)
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [requireExplicitPolicy]
|
||||
* @property {string} [inhibitPolicyMapping]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.Primitive({
|
||||
name: (names.requireExplicitPolicy || ""),
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
}
|
||||
}), // IMPLICIT integer value
|
||||
new asn1js.Primitive({
|
||||
name: (names.inhibitPolicyMapping || ""),
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 1 // [1]
|
||||
}
|
||||
}) // IMPLICIT integer value
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"requireExplicitPolicy",
|
||||
"inhibitPolicyMapping"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
PolicyConstraints.schema({
|
||||
names: {
|
||||
requireExplicitPolicy: "requireExplicitPolicy",
|
||||
inhibitPolicyMapping: "inhibitPolicyMapping"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for PolicyConstraints");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
if("requireExplicitPolicy" in asn1.result)
|
||||
{
|
||||
const field1 = asn1.result.requireExplicitPolicy;
|
||||
|
||||
field1.idBlock.tagClass = 1; // UNIVERSAL
|
||||
field1.idBlock.tagNumber = 2; // INTEGER
|
||||
|
||||
const ber1 = field1.toBER(false);
|
||||
const int1 = asn1js.fromBER(ber1);
|
||||
|
||||
this.requireExplicitPolicy = int1.result.valueBlock.valueDec;
|
||||
}
|
||||
|
||||
if("inhibitPolicyMapping" in asn1.result)
|
||||
{
|
||||
const field2 = asn1.result.inhibitPolicyMapping;
|
||||
|
||||
field2.idBlock.tagClass = 1; // UNIVERSAL
|
||||
field2.idBlock.tagNumber = 2; // INTEGER
|
||||
|
||||
const ber2 = field2.toBER(false);
|
||||
const int2 = asn1js.fromBER(ber2);
|
||||
|
||||
this.inhibitPolicyMapping = int2.result.valueBlock.valueDec;
|
||||
}
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Create correct values for output sequence
|
||||
const outputArray = [];
|
||||
|
||||
if("requireExplicitPolicy" in this)
|
||||
{
|
||||
const int1 = new asn1js.Integer({ value: this.requireExplicitPolicy });
|
||||
|
||||
int1.idBlock.tagClass = 3; // CONTEXT-SPECIFIC
|
||||
int1.idBlock.tagNumber = 0; // [0]
|
||||
|
||||
outputArray.push(int1);
|
||||
}
|
||||
|
||||
if("inhibitPolicyMapping" in this)
|
||||
{
|
||||
const int2 = new asn1js.Integer({ value: this.inhibitPolicyMapping });
|
||||
|
||||
int2.idBlock.tagClass = 3; // CONTEXT-SPECIFIC
|
||||
int2.idBlock.tagNumber = 1; // [1]
|
||||
|
||||
outputArray.push(int2);
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: outputArray
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
const object = {};
|
||||
|
||||
if("requireExplicitPolicy" in this)
|
||||
object.requireExplicitPolicy = this.requireExplicitPolicy;
|
||||
|
||||
if("inhibitPolicyMapping" in this)
|
||||
object.inhibitPolicyMapping = this.inhibitPolicyMapping;
|
||||
|
||||
return object;
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
178
core/third-party/pkijs/PolicyInformation.js
vendored
Normal file
178
core/third-party/pkijs/PolicyInformation.js
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import PolicyQualifierInfo from "./PolicyQualifierInfo.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5280
|
||||
*/
|
||||
export default class PolicyInformation
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for PolicyInformation class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {string}
|
||||
* @desc policyIdentifier
|
||||
*/
|
||||
this.policyIdentifier = getParametersValue(parameters, "policyIdentifier", PolicyInformation.defaultValues("policyIdentifier"));
|
||||
|
||||
if("policyQualifiers" in parameters)
|
||||
/**
|
||||
* @type {Array.<PolicyQualifierInfo>}
|
||||
* @desc Value of the TIME class
|
||||
*/
|
||||
this.policyQualifiers = getParametersValue(parameters, "policyQualifiers", PolicyInformation.defaultValues("policyQualifiers"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "policyIdentifier":
|
||||
return "";
|
||||
case "policyQualifiers":
|
||||
return [];
|
||||
default:
|
||||
throw new Error(`Invalid member name for PolicyInformation class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* PolicyInformation ::= SEQUENCE {
|
||||
* policyIdentifier CertPolicyId,
|
||||
* policyQualifiers SEQUENCE SIZE (1..MAX) OF
|
||||
* PolicyQualifierInfo OPTIONAL }
|
||||
*
|
||||
* CertPolicyId ::= OBJECT IDENTIFIER
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [policyIdentifier]
|
||||
* @property {string} [policyQualifiers]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.ObjectIdentifier({ name: (names.policyIdentifier || "") }),
|
||||
new asn1js.Sequence({
|
||||
optional: true,
|
||||
value: [
|
||||
new asn1js.Repeated({
|
||||
name: (names.policyQualifiers || ""),
|
||||
value: PolicyQualifierInfo.schema()
|
||||
})
|
||||
]
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"policyIdentifier",
|
||||
"policyQualifiers"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
PolicyInformation.schema({
|
||||
names: {
|
||||
policyIdentifier: "policyIdentifier",
|
||||
policyQualifiers: "policyQualifiers"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for PolicyInformation");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.policyIdentifier = asn1.result.policyIdentifier.valueBlock.toString();
|
||||
|
||||
if("policyQualifiers" in asn1.result)
|
||||
this.policyQualifiers = Array.from(asn1.result.policyQualifiers, element => new PolicyQualifierInfo({ schema: element }));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Create array for output sequence
|
||||
const outputArray = [];
|
||||
|
||||
outputArray.push(new asn1js.ObjectIdentifier({ value: this.policyIdentifier }));
|
||||
|
||||
if("policyQualifiers" in this)
|
||||
{
|
||||
outputArray.push(new asn1js.Sequence({
|
||||
value: Array.from(this.policyQualifiers, element => element.toSchema())
|
||||
}));
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: outputArray
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
const object = {
|
||||
policyIdentifier: this.policyIdentifier
|
||||
};
|
||||
|
||||
if("policyQualifiers" in this)
|
||||
object.policyQualifiers = Array.from(this.policyQualifiers, element => element.toJSON());
|
||||
|
||||
return object;
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
148
core/third-party/pkijs/PolicyMapping.js
vendored
Normal file
148
core/third-party/pkijs/PolicyMapping.js
vendored
Normal file
@@ -0,0 +1,148 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5280
|
||||
*/
|
||||
export default class PolicyMapping
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for PolicyMapping class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {string}
|
||||
* @desc issuerDomainPolicy
|
||||
*/
|
||||
this.issuerDomainPolicy = getParametersValue(parameters, "issuerDomainPolicy", PolicyMapping.defaultValues("issuerDomainPolicy"));
|
||||
/**
|
||||
* @type {string}
|
||||
* @desc subjectDomainPolicy
|
||||
*/
|
||||
this.subjectDomainPolicy = getParametersValue(parameters, "subjectDomainPolicy", PolicyMapping.defaultValues("subjectDomainPolicy"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "issuerDomainPolicy":
|
||||
return "";
|
||||
case "subjectDomainPolicy":
|
||||
return "";
|
||||
default:
|
||||
throw new Error(`Invalid member name for PolicyMapping class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* PolicyMapping ::= SEQUENCE {
|
||||
* issuerDomainPolicy CertPolicyId,
|
||||
* subjectDomainPolicy CertPolicyId }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [issuerDomainPolicy]
|
||||
* @property {string} [subjectDomainPolicy]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.ObjectIdentifier({ name: (names.issuerDomainPolicy || "") }),
|
||||
new asn1js.ObjectIdentifier({ name: (names.subjectDomainPolicy || "") })
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"issuerDomainPolicy",
|
||||
"subjectDomainPolicy"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
PolicyMapping.schema({
|
||||
names: {
|
||||
issuerDomainPolicy: "issuerDomainPolicy",
|
||||
subjectDomainPolicy: "subjectDomainPolicy"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for PolicyMapping");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.issuerDomainPolicy = asn1.result.issuerDomainPolicy.valueBlock.toString();
|
||||
this.subjectDomainPolicy = asn1.result.subjectDomainPolicy.valueBlock.toString();
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: [
|
||||
new asn1js.ObjectIdentifier({ value: this.issuerDomainPolicy }),
|
||||
new asn1js.ObjectIdentifier({ value: this.subjectDomainPolicy })
|
||||
]
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
return {
|
||||
issuerDomainPolicy: this.issuerDomainPolicy,
|
||||
subjectDomainPolicy: this.subjectDomainPolicy
|
||||
};
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
135
core/third-party/pkijs/PolicyMappings.js
vendored
Normal file
135
core/third-party/pkijs/PolicyMappings.js
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import PolicyMapping from "./PolicyMapping.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5280
|
||||
*/
|
||||
export default class PolicyMappings
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for PolicyMappings class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {Array.<PolicyMapping>}
|
||||
* @desc mappings
|
||||
*/
|
||||
this.mappings = getParametersValue(parameters, "mappings", PolicyMappings.defaultValues("mappings"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "mappings":
|
||||
return [];
|
||||
default:
|
||||
throw new Error(`Invalid member name for PolicyMappings class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* PolicyMappings ::= SEQUENCE SIZE (1..MAX) OF PolicyMapping
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [utcTimeName] Name for "utcTimeName" choice
|
||||
* @property {string} [generalTimeName] Name for "generalTimeName" choice
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.Repeated({
|
||||
name: (names.mappings || ""),
|
||||
value: PolicyMapping.schema()
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"mappings"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
PolicyMappings.schema({
|
||||
names: {
|
||||
mappings: "mappings"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for PolicyMappings");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.mappings = Array.from(asn1.result.mappings, element => new PolicyMapping({ schema: element }));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: Array.from(this.mappings, element => element.toSchema())
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
return {
|
||||
mappings: Array.from(this.mappings, element => element.toJSON())
|
||||
};
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
154
core/third-party/pkijs/PolicyQualifierInfo.js
vendored
Normal file
154
core/third-party/pkijs/PolicyQualifierInfo.js
vendored
Normal file
@@ -0,0 +1,154 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5280
|
||||
*/
|
||||
export default class PolicyQualifierInfo
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for PolicyQualifierInfo class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {string}
|
||||
* @desc policyQualifierId
|
||||
*/
|
||||
this.policyQualifierId = getParametersValue(parameters, "policyQualifierId", PolicyQualifierInfo.defaultValues("policyQualifierId"));
|
||||
/**
|
||||
* @type {Object}
|
||||
* @desc qualifier
|
||||
*/
|
||||
this.qualifier = getParametersValue(parameters, "qualifier", PolicyQualifierInfo.defaultValues("qualifier"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "policyQualifierId":
|
||||
return "";
|
||||
case "qualifier":
|
||||
return new asn1js.Any();
|
||||
default:
|
||||
throw new Error(`Invalid member name for PolicyQualifierInfo class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* PolicyQualifierInfo ::= SEQUENCE {
|
||||
* policyQualifierId PolicyQualifierId,
|
||||
* qualifier ANY DEFINED BY policyQualifierId }
|
||||
*
|
||||
* id-qt OBJECT IDENTIFIER ::= { id-pkix 2 }
|
||||
* id-qt-cps OBJECT IDENTIFIER ::= { id-qt 1 }
|
||||
* id-qt-unotice OBJECT IDENTIFIER ::= { id-qt 2 }
|
||||
*
|
||||
* PolicyQualifierId ::= OBJECT IDENTIFIER ( id-qt-cps | id-qt-unotice )
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [policyQualifierId]
|
||||
* @property {string} [qualifier]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.ObjectIdentifier({ name: (names.policyQualifierId || "") }),
|
||||
new asn1js.Any({ name: (names.qualifier || "") })
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"policyQualifierId",
|
||||
"qualifier"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
PolicyQualifierInfo.schema({
|
||||
names: {
|
||||
policyQualifierId: "policyQualifierId",
|
||||
qualifier: "qualifier"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for PolicyQualifierInfo");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.policyQualifierId = asn1.result.policyQualifierId.valueBlock.toString();
|
||||
this.qualifier = asn1.result.qualifier;
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: [
|
||||
new asn1js.ObjectIdentifier({ value: this.policyQualifierId }),
|
||||
this.qualifier
|
||||
]
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
return {
|
||||
policyQualifierId: this.policyQualifierId,
|
||||
qualifier: this.qualifier.toJSON()
|
||||
};
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
329
core/third-party/pkijs/PrivateKeyInfo.js
vendored
Normal file
329
core/third-party/pkijs/PrivateKeyInfo.js
vendored
Normal file
@@ -0,0 +1,329 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import AlgorithmIdentifier from "./AlgorithmIdentifier.js";
|
||||
import Attribute from "./Attribute.js";
|
||||
import ECPrivateKey from "./ECPrivateKey.js";
|
||||
import RSAPrivateKey from "./RSAPrivateKey.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5208
|
||||
*/
|
||||
export default class PrivateKeyInfo
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for PrivateKeyInfo class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {number}
|
||||
* @desc version
|
||||
*/
|
||||
this.version = getParametersValue(parameters, "version", PrivateKeyInfo.defaultValues("version"));
|
||||
/**
|
||||
* @type {AlgorithmIdentifier}
|
||||
* @desc privateKeyAlgorithm
|
||||
*/
|
||||
this.privateKeyAlgorithm = getParametersValue(parameters, "privateKeyAlgorithm", PrivateKeyInfo.defaultValues("privateKeyAlgorithm"));
|
||||
/**
|
||||
* @type {OctetString}
|
||||
* @desc privateKey
|
||||
*/
|
||||
this.privateKey = getParametersValue(parameters, "privateKey", PrivateKeyInfo.defaultValues("privateKey"));
|
||||
|
||||
if("attributes" in parameters)
|
||||
/**
|
||||
* @type {Array.<Attribute>}
|
||||
* @desc attributes
|
||||
*/
|
||||
this.attributes = getParametersValue(parameters, "attributes", PrivateKeyInfo.defaultValues("attributes"));
|
||||
|
||||
if("parsedKey" in parameters)
|
||||
/**
|
||||
* @type {ECPrivateKey|RSAPrivateKey}
|
||||
* @desc Parsed public key value
|
||||
*/
|
||||
this.parsedKey = getParametersValue(parameters, "parsedKey", PrivateKeyInfo.defaultValues("parsedKey"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
//region If input argument array contains "json" for this object
|
||||
if("json" in parameters)
|
||||
this.fromJSON(parameters.json);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "version":
|
||||
return 0;
|
||||
case "privateKeyAlgorithm":
|
||||
return new AlgorithmIdentifier();
|
||||
case "privateKey":
|
||||
return new asn1js.OctetString();
|
||||
case "attributes":
|
||||
return [];
|
||||
case "parsedKey":
|
||||
return {};
|
||||
default:
|
||||
throw new Error(`Invalid member name for PrivateKeyInfo class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* PrivateKeyInfo ::= SEQUENCE {
|
||||
* version Version,
|
||||
* privateKeyAlgorithm AlgorithmIdentifier {{PrivateKeyAlgorithms}},
|
||||
* privateKey PrivateKey,
|
||||
* attributes [0] Attributes OPTIONAL }
|
||||
*
|
||||
* Version ::= INTEGER {v1(0)} (v1,...)
|
||||
*
|
||||
* PrivateKey ::= OCTET STRING
|
||||
*
|
||||
* Attributes ::= SET OF Attribute
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [version]
|
||||
* @property {string} [privateKeyAlgorithm]
|
||||
* @property {string} [privateKey]
|
||||
* @property {string} [attributes]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.Integer({ name: (names.version || "") }),
|
||||
AlgorithmIdentifier.schema(names.privateKeyAlgorithm || {}),
|
||||
new asn1js.OctetString({ name: (names.privateKey || "") }),
|
||||
new asn1js.Constructed({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: [
|
||||
new asn1js.Repeated({
|
||||
name: (names.attributes || ""),
|
||||
value: Attribute.schema()
|
||||
})
|
||||
]
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"version",
|
||||
"privateKeyAlgorithm",
|
||||
"privateKey",
|
||||
"attributes"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
PrivateKeyInfo.schema({
|
||||
names: {
|
||||
version: "version",
|
||||
privateKeyAlgorithm: {
|
||||
names: {
|
||||
blockName: "privateKeyAlgorithm"
|
||||
}
|
||||
},
|
||||
privateKey: "privateKey",
|
||||
attributes: "attributes"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for PrivateKeyInfo");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.version = asn1.result.version.valueBlock.valueDec;
|
||||
this.privateKeyAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.privateKeyAlgorithm });
|
||||
this.privateKey = asn1.result.privateKey;
|
||||
|
||||
if("attributes" in asn1.result)
|
||||
this.attributes = Array.from(asn1.result.attributes, element => new Attribute({ schema: element }));
|
||||
|
||||
switch(this.privateKeyAlgorithm.algorithmId)
|
||||
{
|
||||
case "1.2.840.113549.1.1.1": // RSA
|
||||
{
|
||||
const privateKeyASN1 = asn1js.fromBER(this.privateKey.valueBlock.valueHex);
|
||||
if(privateKeyASN1.offset !== (-1))
|
||||
this.parsedKey = new RSAPrivateKey({ schema: privateKeyASN1.result });
|
||||
}
|
||||
break;
|
||||
case "1.2.840.10045.2.1": // ECDSA
|
||||
if("algorithmParams" in this.privateKeyAlgorithm)
|
||||
{
|
||||
if(this.privateKeyAlgorithm.algorithmParams instanceof asn1js.ObjectIdentifier)
|
||||
{
|
||||
const privateKeyASN1 = asn1js.fromBER(this.privateKey.valueBlock.valueHex);
|
||||
if(privateKeyASN1.offset !== (-1))
|
||||
{
|
||||
this.parsedKey = new ECPrivateKey({
|
||||
namedCurve: this.privateKeyAlgorithm.algorithmParams.valueBlock.toString(),
|
||||
schema: privateKeyASN1.result
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Create array for output sequence
|
||||
const outputArray = [
|
||||
new asn1js.Integer({ value: this.version }),
|
||||
this.privateKeyAlgorithm.toSchema(),
|
||||
this.privateKey
|
||||
];
|
||||
|
||||
if("attributes" in this)
|
||||
{
|
||||
outputArray.push(new asn1js.Constructed({
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
value: Array.from(this.attributes, element => element.toSchema())
|
||||
}));
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: outputArray
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
//region Return common value in case we do not have enough info fo making JWK
|
||||
if(("parsedKey" in this) === false)
|
||||
{
|
||||
const object = {
|
||||
version: this.version,
|
||||
privateKeyAlgorithm: this.privateKeyAlgorithm.toJSON(),
|
||||
privateKey: this.privateKey.toJSON()
|
||||
};
|
||||
|
||||
if("attributes" in this)
|
||||
object.attributes = Array.from(this.attributes, element => element.toJSON());
|
||||
|
||||
return object;
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region Making JWK
|
||||
const jwk = {};
|
||||
|
||||
switch(this.privateKeyAlgorithm.algorithmId)
|
||||
{
|
||||
case "1.2.840.10045.2.1": // ECDSA
|
||||
jwk.kty = "EC";
|
||||
break;
|
||||
case "1.2.840.113549.1.1.1": // RSA
|
||||
jwk.kty = "RSA";
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
const publicKeyJWK = this.parsedKey.toJSON();
|
||||
|
||||
for(const key of Object.keys(publicKeyJWK))
|
||||
jwk[key] = publicKeyJWK[key];
|
||||
|
||||
return jwk;
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert JSON value into current object
|
||||
* @param {Object} json
|
||||
*/
|
||||
fromJSON(json)
|
||||
{
|
||||
if("kty" in json)
|
||||
{
|
||||
switch(json.kty.toUpperCase())
|
||||
{
|
||||
case "EC":
|
||||
this.parsedKey = new ECPrivateKey({ json });
|
||||
|
||||
this.privateKeyAlgorithm = new AlgorithmIdentifier({
|
||||
algorithmId: "1.2.840.10045.2.1",
|
||||
algorithmParams: new asn1js.ObjectIdentifier({ value: this.parsedKey.namedCurve })
|
||||
});
|
||||
break;
|
||||
case "RSA":
|
||||
this.parsedKey = new RSAPrivateKey({ json });
|
||||
|
||||
this.privateKeyAlgorithm = new AlgorithmIdentifier({
|
||||
algorithmId: "1.2.840.113549.1.1.1",
|
||||
algorithmParams: new asn1js.Null()
|
||||
});
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Invalid value for "kty" parameter: ${json.kty}`);
|
||||
}
|
||||
|
||||
this.privateKey = new asn1js.OctetString({ valueHex: this.parsedKey.toSchema().toBER(false) });
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
207
core/third-party/pkijs/PrivateKeyUsagePeriod.js
vendored
Normal file
207
core/third-party/pkijs/PrivateKeyUsagePeriod.js
vendored
Normal file
@@ -0,0 +1,207 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5280
|
||||
*/
|
||||
export default class PrivateKeyUsagePeriod
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for PrivateKeyUsagePeriod class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
if("notBefore" in parameters)
|
||||
/**
|
||||
* @type {Date}
|
||||
* @desc notBefore
|
||||
*/
|
||||
this.notBefore = getParametersValue(parameters, "notBefore", PrivateKeyUsagePeriod.defaultValues("notBefore"));
|
||||
|
||||
if("notAfter" in parameters)
|
||||
/**
|
||||
* @type {Date}
|
||||
* @desc notAfter
|
||||
*/
|
||||
this.notAfter = getParametersValue(parameters, "notAfter", PrivateKeyUsagePeriod.defaultValues("notAfter"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "notBefore":
|
||||
return new Date();
|
||||
case "notAfter":
|
||||
return new Date();
|
||||
default:
|
||||
throw new Error(`Invalid member name for PrivateKeyUsagePeriod class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* PrivateKeyUsagePeriod OID ::= 2.5.29.16
|
||||
*
|
||||
* PrivateKeyUsagePeriod ::= SEQUENCE {
|
||||
* notBefore [0] GeneralizedTime OPTIONAL,
|
||||
* notAfter [1] GeneralizedTime OPTIONAL }
|
||||
* -- either notBefore or notAfter MUST be present
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [notBefore]
|
||||
* @property {string} [notAfter]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
new asn1js.Primitive({
|
||||
name: (names.notBefore || ""),
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
}
|
||||
}),
|
||||
new asn1js.Primitive({
|
||||
name: (names.notAfter || ""),
|
||||
optional: true,
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 1 // [1]
|
||||
}
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"notBefore",
|
||||
"notAfter"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
PrivateKeyUsagePeriod.schema({
|
||||
names: {
|
||||
notBefore: "notBefore",
|
||||
notAfter: "notAfter"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for PrivateKeyUsagePeriod");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
if("notBefore" in asn1.result)
|
||||
{
|
||||
const localNotBefore = new asn1js.GeneralizedTime();
|
||||
localNotBefore.fromBuffer(asn1.result.notBefore.valueBlock.valueHex);
|
||||
this.notBefore = localNotBefore.toDate();
|
||||
}
|
||||
|
||||
if("notAfter" in asn1.result)
|
||||
{
|
||||
const localNotAfter = new asn1js.GeneralizedTime({ valueHex: asn1.result.notAfter.valueBlock.valueHex });
|
||||
localNotAfter.fromBuffer(asn1.result.notAfter.valueBlock.valueHex);
|
||||
this.notAfter = localNotAfter.toDate();
|
||||
}
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Create array for output sequence
|
||||
const outputArray = [];
|
||||
|
||||
if("notBefore" in this)
|
||||
{
|
||||
outputArray.push(new asn1js.Primitive({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 0 // [0]
|
||||
},
|
||||
valueHex: (new asn1js.GeneralizedTime({ valueDate: this.notBefore })).valueBlock.valueHex
|
||||
}));
|
||||
}
|
||||
|
||||
if("notAfter" in this)
|
||||
{
|
||||
outputArray.push(new asn1js.Primitive({
|
||||
idBlock: {
|
||||
tagClass: 3, // CONTEXT-SPECIFIC
|
||||
tagNumber: 1 // [1]
|
||||
},
|
||||
valueHex: (new asn1js.GeneralizedTime({ valueDate: this.notAfter })).valueBlock.valueHex
|
||||
}));
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: outputArray
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
const object = {};
|
||||
|
||||
if("notBefore" in this)
|
||||
object.notBefore = this.notBefore;
|
||||
|
||||
if("notAfter" in this)
|
||||
object.notAfter = this.notAfter;
|
||||
|
||||
return object;
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
311
core/third-party/pkijs/PublicKeyInfo.js
vendored
Normal file
311
core/third-party/pkijs/PublicKeyInfo.js
vendored
Normal file
@@ -0,0 +1,311 @@
|
||||
import * as asn1js from "./asn1.js";
|
||||
import { getParametersValue, clearProps } from "./pvutils.js";
|
||||
import { getCrypto } from "./common.js";
|
||||
import AlgorithmIdentifier from "./AlgorithmIdentifier.js";
|
||||
import ECPublicKey from "./ECPublicKey.js";
|
||||
import RSAPublicKey from "./RSAPublicKey.js";
|
||||
//**************************************************************************************
|
||||
/**
|
||||
* Class from RFC5280
|
||||
*/
|
||||
export default class PublicKeyInfo
|
||||
{
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Constructor for PublicKeyInfo class
|
||||
* @param {Object} [parameters={}]
|
||||
* @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
|
||||
*/
|
||||
constructor(parameters = {})
|
||||
{
|
||||
//region Internal properties of the object
|
||||
/**
|
||||
* @type {AlgorithmIdentifier}
|
||||
* @desc Algorithm identifier
|
||||
*/
|
||||
this.algorithm = getParametersValue(parameters, "algorithm", PublicKeyInfo.defaultValues("algorithm"));
|
||||
/**
|
||||
* @type {BitString}
|
||||
* @desc Subject public key value
|
||||
*/
|
||||
this.subjectPublicKey = getParametersValue(parameters, "subjectPublicKey", PublicKeyInfo.defaultValues("subjectPublicKey"));
|
||||
|
||||
if("parsedKey" in parameters)
|
||||
/**
|
||||
* @type {ECPublicKey|RSAPublicKey}
|
||||
* @desc Parsed public key value
|
||||
*/
|
||||
this.parsedKey = getParametersValue(parameters, "parsedKey", PublicKeyInfo.defaultValues("parsedKey"));
|
||||
//endregion
|
||||
|
||||
//region If input argument array contains "schema" for this object
|
||||
if("schema" in parameters)
|
||||
this.fromSchema(parameters.schema);
|
||||
//endregion
|
||||
//region If input argument array contains "json" for this object
|
||||
if("json" in parameters)
|
||||
this.fromJSON(parameters.json);
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return default values for all class members
|
||||
* @param {string} memberName String name for a class member
|
||||
*/
|
||||
static defaultValues(memberName)
|
||||
{
|
||||
switch(memberName)
|
||||
{
|
||||
case "algorithm":
|
||||
return new AlgorithmIdentifier();
|
||||
case "subjectPublicKey":
|
||||
return new asn1js.BitString();
|
||||
default:
|
||||
throw new Error(`Invalid member name for PublicKeyInfo class: ${memberName}`);
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Return value of pre-defined ASN.1 schema for current class
|
||||
*
|
||||
* ASN.1 schema:
|
||||
* ```asn1
|
||||
* SubjectPublicKeyInfo ::= Sequence {
|
||||
* algorithm AlgorithmIdentifier,
|
||||
* subjectPublicKey BIT STRING }
|
||||
* ```
|
||||
*
|
||||
* @param {Object} parameters Input parameters for the schema
|
||||
* @returns {Object} asn1js schema object
|
||||
*/
|
||||
static schema(parameters = {})
|
||||
{
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {string} [blockName]
|
||||
* @property {string} [algorithm]
|
||||
* @property {string} [subjectPublicKey]
|
||||
*/
|
||||
const names = getParametersValue(parameters, "names", {});
|
||||
|
||||
return (new asn1js.Sequence({
|
||||
name: (names.blockName || ""),
|
||||
value: [
|
||||
AlgorithmIdentifier.schema(names.algorithm || {}),
|
||||
new asn1js.BitString({ name: (names.subjectPublicKey || "") })
|
||||
]
|
||||
}));
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert parsed asn1js object into current class
|
||||
* @param {!Object} schema
|
||||
*/
|
||||
fromSchema(schema)
|
||||
{
|
||||
//region Clear input data first
|
||||
clearProps(schema, [
|
||||
"algorithm",
|
||||
"subjectPublicKey"
|
||||
]);
|
||||
//endregion
|
||||
|
||||
//region Check the schema is valid
|
||||
const asn1 = asn1js.compareSchema(schema,
|
||||
schema,
|
||||
PublicKeyInfo.schema({
|
||||
names: {
|
||||
algorithm: {
|
||||
names: {
|
||||
blockName: "algorithm"
|
||||
}
|
||||
},
|
||||
subjectPublicKey: "subjectPublicKey"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if(asn1.verified === false)
|
||||
throw new Error("Object's schema was not verified against input data for PublicKeyInfo");
|
||||
//endregion
|
||||
|
||||
//region Get internal properties from parsed schema
|
||||
this.algorithm = new AlgorithmIdentifier({ schema: asn1.result.algorithm });
|
||||
this.subjectPublicKey = asn1.result.subjectPublicKey;
|
||||
|
||||
switch(this.algorithm.algorithmId)
|
||||
{
|
||||
case "1.2.840.10045.2.1": // ECDSA
|
||||
if("algorithmParams" in this.algorithm)
|
||||
{
|
||||
if(this.algorithm.algorithmParams.constructor.blockName() === asn1js.ObjectIdentifier.blockName())
|
||||
{
|
||||
try
|
||||
{
|
||||
this.parsedKey = new ECPublicKey({
|
||||
namedCurve: this.algorithm.algorithmParams.valueBlock.toString(),
|
||||
schema: this.subjectPublicKey.valueBlock.valueHex
|
||||
});
|
||||
}
|
||||
catch(ex){} // Could be a problems during recognision of internal public key data here. Let's ignore them.
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "1.2.840.113549.1.1.1": // RSA
|
||||
{
|
||||
const publicKeyASN1 = asn1js.fromBER(this.subjectPublicKey.valueBlock.valueHex);
|
||||
if(publicKeyASN1.offset !== (-1))
|
||||
{
|
||||
try
|
||||
{
|
||||
this.parsedKey = new RSAPublicKey({ schema: publicKeyASN1.result });
|
||||
}
|
||||
catch(ex){} // Could be a problems during recognision of internal public key data here. Let's ignore them.
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert current object to asn1js object and set correct values
|
||||
* @returns {Object} asn1js object
|
||||
*/
|
||||
toSchema()
|
||||
{
|
||||
//region Construct and return new ASN.1 schema for this object
|
||||
return (new asn1js.Sequence({
|
||||
value: [
|
||||
this.algorithm.toSchema(),
|
||||
this.subjectPublicKey
|
||||
]
|
||||
}));
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convertion for the class to JSON object
|
||||
* @returns {Object}
|
||||
*/
|
||||
toJSON()
|
||||
{
|
||||
//region Return common value in case we do not have enough info fo making JWK
|
||||
if(("parsedKey" in this) === false)
|
||||
{
|
||||
return {
|
||||
algorithm: this.algorithm.toJSON(),
|
||||
subjectPublicKey: this.subjectPublicKey.toJSON()
|
||||
};
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region Making JWK
|
||||
const jwk = {};
|
||||
|
||||
switch(this.algorithm.algorithmId)
|
||||
{
|
||||
case "1.2.840.10045.2.1": // ECDSA
|
||||
jwk.kty = "EC";
|
||||
break;
|
||||
case "1.2.840.113549.1.1.1": // RSA
|
||||
jwk.kty = "RSA";
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
const publicKeyJWK = this.parsedKey.toJSON();
|
||||
|
||||
for(const key of Object.keys(publicKeyJWK))
|
||||
jwk[key] = publicKeyJWK[key];
|
||||
|
||||
return jwk;
|
||||
//endregion
|
||||
}
|
||||
//**********************************************************************************
|
||||
/**
|
||||
* Convert JSON value into current object
|
||||
* @param {Object} json
|
||||
*/
|
||||
fromJSON(json)
|
||||
{
|
||||
if("kty" in json)
|
||||
{
|
||||
switch(json.kty.toUpperCase())
|
||||
{
|
||||
case "EC":
|
||||
this.parsedKey = new ECPublicKey({ json });
|
||||
|
||||
this.algorithm = new AlgorithmIdentifier({
|
||||
algorithmId: "1.2.840.10045.2.1",
|
||||
algorithmParams: new asn1js.ObjectIdentifier({ value: this.parsedKey.namedCurve })
|
||||
});
|
||||
break;
|
||||
case "RSA":
|
||||
this.parsedKey = new RSAPublicKey({ json });
|
||||
|
||||
this.algorithm = new AlgorithmIdentifier({
|
||||
algorithmId: "1.2.840.113549.1.1.1",
|
||||
algorithmParams: new asn1js.Null()
|
||||
});
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Invalid value for "kty" parameter: ${json.kty}`);
|
||||
}
|
||||
|
||||
this.subjectPublicKey = new asn1js.BitString({ valueHex: this.parsedKey.toSchema().toBER(false) });
|
||||
}
|
||||
}
|
||||
//**********************************************************************************
|
||||
importKey(publicKey)
|
||||
{
|
||||
//region Initial variables
|
||||
let sequence = Promise.resolve();
|
||||
const _this = this;
|
||||
//endregion
|
||||
|
||||
//region Initial check
|
||||
if(typeof publicKey === "undefined")
|
||||
return Promise.reject("Need to provide publicKey input parameter");
|
||||
//endregion
|
||||
|
||||
//region Get a "crypto" extension
|
||||
const crypto = getCrypto();
|
||||
if(typeof crypto === "undefined")
|
||||
return Promise.reject("Unable to create WebCrypto object");
|
||||
//endregion
|
||||
|
||||
//region Export public key
|
||||
sequence = sequence.then(() =>
|
||||
crypto.exportKey("spki", publicKey));
|
||||
//endregion
|
||||
|
||||
//region Initialize internal variables by parsing exported value
|
||||
sequence = sequence.then(
|
||||
/**
|
||||
* @param {ArrayBuffer} exportedKey
|
||||
*/
|
||||
exportedKey =>
|
||||
{
|
||||
const asn1 = asn1js.fromBER(exportedKey);
|
||||
try
|
||||
{
|
||||
_this.fromSchema(asn1.result);
|
||||
}
|
||||
catch(exception)
|
||||
{
|
||||
return Promise.reject("Error during initializing object from schema");
|
||||
}
|
||||
|
||||
return undefined;
|
||||
},
|
||||
error => Promise.reject(`Error during exporting public key: ${error}`)
|
||||
);
|
||||
//endregion
|
||||
|
||||
return sequence;
|
||||
}
|
||||
//**********************************************************************************
|
||||
}
|
||||
//**************************************************************************************
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user