Skip to content

Commit

Permalink
Add cert storage
Browse files Browse the repository at this point in the history
- working methods `key`, `getItem`
  • Loading branch information
microshine committed Mar 16, 2017
1 parent f36ede0 commit 535322e
Show file tree
Hide file tree
Showing 4 changed files with 208 additions and 4 deletions.
62 changes: 62 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,68 @@ TODO: ADD THREATS FROM WEAK CRYPTOGRAPHY

TODO: ADD THREATS FOR IMPROPER USE OF CRYPTOGRAPHY

## Using

### Provider

```javascript
var wcp11 = require("node-webcrypto-p11");
const provider = new wcp11.Provider("path/to/pkcs11.so");

let tokens = 0;
provider
.on("listening", (info) => {
console.log("listening");
console.log(info);
console.log(`Providers: ${info.providers.length}`);

tokens = info.providers.length;
})
.on("token", (info) => {
console.log("token:", tokens > info.providers.length ? "removed" : "inserted");
console.log(`Providers: ${info.providers.length}`);
tokens = info.providers.length;
})
.on("error", (e) => {
console.error(e);
})

provider.open();
```

### Crypto

Example: Generates `ECDSA` key pair with named curve `P-256` and signs/verifies text message.

```javascript
var wcp11 = require("node-webcrypto-p11");

var config = {
library: "/usr/local/lib/softhsm/libsofthsm2.so",
name: "SoftHSM v2.0",
slot: 0,
sessionFlags: 4, // SERIAL_SESSION
pin: "12345"
}

var crypto = new wcp11.WebCrypto(config);

crypto.subtle.generateKey({name: "ECDSA", namedCurve: "P-256"}, false, ["sign", "verify"])
.then((keys) => {
return crypto.subtle.sign({name: "ECDSA", hash: "SHA-256"}, keys.privateKey, new Buffer("Hello world!"))
.then((signature) => {
console.log(`Signature: ${signature}`);
return crypto.subtle.verify({name: "ECDSA", hash: "SHA-256"}, keys.publicKey, signature, new Buffer("Hello world!"))
})
.then((ok) => {
console.log(`Verification: ${ok}`);
});
})
.catch((err) => {
console.error(err);
});
```

## Bug Reporting
Please report bugs either as pull requests or as issues in the issue tracker. Backwater has a full disclosure vulnerability policy. Please do NOT attempt to report any security vulnerability in this code privately to anybody.

Expand Down
139 changes: 139 additions & 0 deletions lib/cert_storage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import * as webcrypto from "webcrypto-core";
const WebCryptoError = webcrypto.WebCryptoError;

import { KeyType, ObjectClass, PublicKey, Session, SessionObject, X509Certificate } from "graphene-pk11";
import { CryptoKey } from "./key";

export class CertificateStorage implements ICertificateStorage {

protected session: Session;

constructor(session: Session) {
this.session = session;
}

public async keys() {
const keys: string[] = [];
[ObjectClass.CERTIFICATE].forEach((objectClass) => {
this.session.find({ class: objectClass }, (obj) => {
const item = obj.toType<any>();
keys.push(this.getName(objectClass, item.id));
});
});
return keys;
}

public async clear() {
this.session.clear();
}

public async getItem(key: string) {
const subjectObject = this.getItemById(key);
if (subjectObject) {
const x509 = subjectObject.toType<X509Certificate>();
const keys = this.session.find({
class: ObjectClass.PUBLIC_KEY,
id: x509.id,
});
if (!keys.length) {
throw new Error("Cannot find public key for Certificate");
}
const p11Key = keys.items(0).toType<PublicKey>();
const alg: any = {};
// name
switch (p11Key.type) {
case KeyType.RSA: {
if (p11Key.verify) {
alg.name = "RSASSA-PKCS1-v1_5";
} else {
alg.name = "RSA-OAEP";
}
alg.hash = { name: "SHA-256" };
break;
}
case KeyType.EC: {
throw new Error(`Not implemented yet`);
}
default:
throw new Error(`Unsupported type of key '${KeyType[p11Key.type] || p11Key.type}'`);
}
// const alg = JSON.parse(p11Key.label);
return {
id: x509.id.toString("hex"),
type: "x509",
publicKey: new CryptoKey(p11Key, alg),
value: new Uint8Array(x509.value).buffer,
} as IX509Certificate;
} else {
return null;
}
}

public key(index: number): string {
throw new Error("Not implemented yet");
}

public async removeItem(key: string) {
const sessionObject = this.getItemById(key);
if (sessionObject) {
sessionObject.destroy();
}
}

public async setItem(key: string, data: ICertificateStorageItem) {
if (!(data instanceof CryptoKey)) {
throw new WebCryptoError("Parameter 2 is not P11CryptoKey");
}
const p11Key = data as CryptoKey;
// don't copy object from token
if (!p11Key.key.token) {
this.session.copy(p11Key.key, {
token: true,
id: new Buffer(key),
label: JSON.stringify(data.algorithm),
});
}
}

public async importCert(type: string, data: ArrayBuffer, algorithm: Algorithm, keyUsages: string[]): Promise<ICertificateStorageItem> {
throw new Error("Method not implemented.");
}

protected getItemById(id: string) {
let key: SessionObject = null;
[ObjectClass.CERTIFICATE].forEach((objectClass) => {
this.session.find({ class: objectClass }, (obj) => {
const item = obj.toType<any>();
if (id === this.getName(objectClass, item.id)) {
key = item;
return false;
}
});
});
return key;
}

/**
* Returns name for item by it's type and id
* Template: <type>-<hex(id)>
*
* @protected
* @param {ObjectClass} type
* @param {Buffer} id
* @returns
*
* @memberOf KeyStorage
*/
protected getName(type: ObjectClass, id: Buffer) {
let name: string;
switch (type) {
case ObjectClass.CERTIFICATE:
name = "x509";
break;
default:
throw new Error(`Unsupported Object type '${type}'`);
}
return `${name}-${id.toString("hex")}`;
}

}
8 changes: 4 additions & 4 deletions lib/typings/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,13 @@ interface ICertificateStorageItem {
}

interface IX509Certificate extends ICertificateStorageItem {
serialNumber: HexString;
issuerName: string;
subjectName: string;
serialNumber?: HexString;
issuerName?: string;
subjectName?: string;
}

interface IX509Request extends ICertificateStorageItem {
subjectName: string;
subjectName?: string;
}

interface ICertificateStorage {
Expand Down
3 changes: 3 additions & 0 deletions lib/webcrypto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Mechanism, Module, Session, Slot } from "graphene-pk11";
import { KeyStorage } from "./key_storage";
import { SubtleCrypto } from "./subtle";
import * as utils from "./utils";
import { CertificateStorage } from "./cert_storage";

const ERR_RANDOM_VALUE_LENGTH = "Failed to execute 'getRandomValues' on 'Crypto': The ArrayBufferView's byte length (%1) exceeds the number of bytes of entropy available via this API (65536).";

Expand All @@ -21,6 +22,7 @@ export class WebCrypto implements NativeCrypto {

public subtle: SubtleCrypto;
public keyStorage: KeyStorage;
public certStorage: CertificateStorage;

private module: Module;
private session: Session;
Expand Down Expand Up @@ -51,6 +53,7 @@ export class WebCrypto implements NativeCrypto {

this.subtle = new SubtleCrypto(this.session);
this.keyStorage = new KeyStorage(this.session);
this.certStorage = new CertificateStorage(this.session);
}

/**
Expand Down

0 comments on commit 535322e

Please sign in to comment.