Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

sigstore

Package Overview
Dependencies
Maintainers
2
Versions
35
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

sigstore - npm Package Compare versions

Comparing version 0.0.1-alpha.4 to 0.0.1-alpha.5

dist/__tests__/__fixtures__/bundles/dsse.d.ts

1

dist/client/error.d.ts

@@ -5,2 +5,3 @@ import fetch from 'make-fetch-happen';

response: Response;
statusCode: number;
constructor(response: Response);

@@ -7,0 +8,0 @@ }

@@ -8,2 +8,3 @@ "use strict";

this.response = response;
this.statusCode = response.status;
}

@@ -10,0 +11,0 @@ }

export declare class VerificationError extends Error {
}
export declare class InvalidBundleError extends Error {
}
export declare class UnsupportedVersionError extends Error {
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.VerificationError = void 0;
exports.UnsupportedVersionError = exports.InvalidBundleError = exports.VerificationError = void 0;
class VerificationError extends Error {
}
exports.VerificationError = VerificationError;
class InvalidBundleError extends Error {
}
exports.InvalidBundleError = InvalidBundleError;
class UnsupportedVersionError extends Error {
}
exports.UnsupportedVersionError = UnsupportedVersionError;

7

dist/sigstore.d.ts
/// <reference types="node" />
import { SerializedEnvelope, SerializedBundle } from './types/bundle';
import { SerializedBundle, SerializedEnvelope } from './types/bundle';
import { GetPublicKeyFunc } from './verify';
export * as utils from './sigstore-utils';

@@ -16,3 +17,5 @@ export declare const DEFAULT_REKOR_BASE_URL = "https://rekor.sigstore.dev";

} & TLogOptions;
export declare type VerifierOptions = TLogOptions;
export declare type VerifierOptions = {
getPublicKey?: GetPublicKeyFunc;
} & TLogOptions;
export declare type Bundle = SerializedBundle;

@@ -19,0 +22,0 @@ export declare type Envelope = SerializedEnvelope;

@@ -88,3 +88,7 @@ "use strict";

const tlogKeys = (0, keys_1.getKeys)();
const verifier = new verify_1.Verifier({ tlog, tlogKeys });
const verifier = new verify_1.Verifier({
tlog,
tlogKeys,
getPublicKey: options.getPublicKey,
});
const b = (0, bundle_1.bundleFromJSON)(bundle);

@@ -91,0 +95,0 @@ return verifier.verifyOffline(b, data);

@@ -46,2 +46,7 @@ "use strict";

function toProposedIntotoV002Entry(envelope, signature) {
// Calculate the value for the payloadHash field in the Rekor entry
const payloadHash = util_1.crypto.hash(envelope.payload).toString('hex');
// Calculate the value for the hash field in the Rekor entry
const envelopeHash = calculateDSSEHash(envelope);
// Collect values for re-creating the DSSE envelope.
// Double-encode payload and signature cause that's what Rekor expects

@@ -52,4 +57,5 @@ const payload = util_1.encoding.base64Encode(envelope.payload.toString('base64'));

const publicKey = util_1.encoding.base64Encode(toPublicKey(signature));
const payloadHash = util_1.crypto.hash(envelope.payload).toString('hex');
// Create the envelop portion first so that we can calculate its hash
// Create the envelope portion of the entry. Note the inclusion of the
// publicKey in the signature struct is not a standard part of a DSSE
// envelope, but is required by Rekor.
const dsse = {

@@ -66,3 +72,2 @@ payloadType: envelope.payloadType,

}
const envelopeHash = util_1.crypto.hash(util_1.json.canonicalize(dsse)).toString('hex');
return {

@@ -80,2 +85,21 @@ apiVersion: '0.0.2',

}
// Calculates the hash of a DSSE envelope for inclusion in a Rekor entry.
// There is no standard way to do this, so the scheme we're using as as
// follows:
// * payload is base64 encoded
// * signature is base64 encoded (only the first signature is used)
// * keyid is included ONLY if it is NOT an empty string
// * The resulting JSON is canonicalized and hashed to a hex string
function calculateDSSEHash(envelope) {
const dsse = {
payloadType: envelope.payloadType,
payload: envelope.payload.toString('base64'),
signatures: [{ sig: envelope.signatures[0].sig.toString('base64') }],
};
// If the keyid is an empty string, Rekor seems to remove it altogether.
if (envelope.signatures[0].keyid.length > 0) {
dsse.signatures[0].keyid = envelope.signatures[0].keyid;
}
return util_1.crypto.hash(util_1.json.canonicalize(dsse)).toString('hex');
}
function toPublicKey(signature) {

@@ -82,0 +106,0 @@ return signature.certificates

@@ -39,7 +39,1 @@ import { HashedRekorV001Schema } from './__generated__/hashedrekord';

}
export interface VerificationPayload {
body: string;
integratedTime: number;
logIndex: number;
logID: string;
}
/// <reference types="node" />
import { KeyObject } from 'crypto';
import { Bundle } from '../types/bundle';
export declare function verifyTLogSET(bundle: Bundle, tlogKeys: Record<string, KeyObject>): void;
export declare function verifyTLogEntries(bundle: Bundle, tlogKeys: Record<string, KeyObject>): void;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.verifyTLogSET = void 0;
exports.verifyTLogEntries = void 0;
const error_1 = require("../error");
const util_1 = require("../util");
const format_1 = require("./format");
// Verifies that all of the tlog entries in the given bundle can be verified.
// Verification is peroformed by re-creating the original Rekor entry from the
// bundle and then verifying the SET against the entry using the corresponding
// key.
function verifyTLogSET(bundle, tlogKeys) {
var _a;
(_a = bundle.verificationData) === null || _a === void 0 ? void 0 : _a.tlogEntries.forEach((entry, index) => {
var _a;
// Re-create the original Rekor verification payload
const payload = toVerificationPayload(bundle, index);
// Canonicalize the payload and turn into a buffer for verification
const data = Buffer.from(util_1.json.canonicalize(payload), 'utf8');
// Find the public key for the transaction log which generated the SET
const publicKey = tlogKeys[payload.logID];
if (!publicKey) {
throw new Error('no key found for logID: ' + payload.logID);
const TLOG_MISMATCH_ERROR_MSG = 'bundle content and tlog entry do not match';
// Verifies that all of the tlog entries in the given bundle.
function verifyTLogEntries(bundle, tlogKeys) {
var _a, _b, _c;
// Extract the signing cert bytes if available
let signingCert;
if (((_b = (_a = bundle.verificationMaterial) === null || _a === void 0 ? void 0 : _a.content) === null || _b === void 0 ? void 0 : _b.$case) === 'x509CertificateChain') {
signingCert =
bundle.verificationMaterial.content.x509CertificateChain.certificates[0]
.rawBytes;
}
// Iterate over the tlog entries and verify each one
(_c = bundle.verificationData) === null || _c === void 0 ? void 0 : _c.tlogEntries.forEach((entry) => {
verifyTLogBody(entry, bundle);
verifyTLogSET(entry, tlogKeys);
// If there is no signing certificate, we can't verify the integrated time
if (signingCert) {
verifyTLogIntegratedTime(entry, signingCert);
}
// Extract the SET from the tlog entry
const signature = (_a = entry.inclusionPromise) === null || _a === void 0 ? void 0 : _a.signedEntryTimestamp;
if (!signature) {
throw new Error('no SET found in bundle');
}
if (!util_1.crypto.verifyBlob(data, publicKey, signature)) {
throw new Error('transparency log SET verification failed');
}
});
}
exports.verifyTLogSET = verifyTLogSET;
// Returns a properly formatted "VerificationPayload" for one of the
// transaction log entires in the given bundle which can be used for SET
// verification.
function toVerificationPayload(bundle, index = 0) {
exports.verifyTLogEntries = verifyTLogEntries;
// Verfifies the SET for the given entry using the provided keys.
function verifyTLogSET(entry, tlogKeys) {
var _a;
// Ensure bundle has tlog entries
const entries = (_a = bundle.verificationData) === null || _a === void 0 ? void 0 : _a.tlogEntries;
if (!entries || entries.length - 1 < index) {
throw new Error('No tlog entries found in bundle');
// Re-create the original Rekor verification payload
const payload = toVerificationPayload(entry);
// Canonicalize the payload and turn into a buffer for verification
const data = Buffer.from(util_1.json.canonicalize(payload), 'utf8');
// Find the public key for the transaction log which generated the SET
const tlogKey = tlogKeys[payload.logID];
if (!tlogKey) {
throw new error_1.VerificationError('no key found for logID: ' + payload.logID);
}
// Rekor metadata
const { integratedTime, logIndex, logId } = entries[index];
if (!logId) {
throw new Error('No logId found in bundle');
// Extract the SET from the tlog entry
const signature = (_a = entry.inclusionPromise) === null || _a === void 0 ? void 0 : _a.signedEntryTimestamp;
if (!signature || signature.length === 0) {
throw new error_1.InvalidBundleError('no SET found in bundle');
}
// Recreate the Rekor entry from the bundle
const body = toVerificationBody(bundle);
return {
body: util_1.encoding.base64Encode(util_1.json.canonicalize(body)),
integratedTime: Number(integratedTime),
logIndex: Number(logIndex),
logID: logId.keyId.toString('hex'),
};
if (!util_1.crypto.verifyBlob(data, tlogKey, signature)) {
throw new error_1.VerificationError('transparency log SET verification failed');
}
}
// Recreates the original Rekor entry from the bundle.
function toVerificationBody(bundle) {
var _a;
// Extract the public key (or signing cert) from the bundle
if (!bundle.verificationMaterial) {
throw new Error('No verification material found in bundle');
// Checks that the tlog integrated time is within the certificate's validity
// period.
function verifyTLogIntegratedTime(entry, signingCert) {
const x509Cert = util_1.x509.parseCertificate(signingCert);
const integratedTime = new Date(Number(entry.integratedTime) * 1000);
if (integratedTime > x509Cert.validTo) {
throw new error_1.VerificationError('tlog integrated time is after certificate expiration');
}
const publicKey = toPublicKey(bundle.verificationMaterial);
switch ((_a = bundle.content) === null || _a === void 0 ? void 0 : _a.$case) {
case 'messageSignature': {
return toMessageSignatureVerificationBody(bundle.content.messageSignature, publicKey);
}
case 'dsseEnvelope': {
return toDSSEVerificationBody(bundle.content.dsseEnvelope, publicKey);
}
if (integratedTime < x509Cert.validFrom) {
throw new error_1.VerificationError('tlog integrated time is before certificate issuance');
}
}
// Compare the given intoto tlog entry to the given bundle
function verifyTLogBody(entry, bundle) {
if (!entry.kindVersion) {
throw new error_1.InvalidBundleError('no kindVersion found in bundle');
}
const { kind, version } = entry.kindVersion;
const body = JSON.parse(entry.canonicalizedBody.toString('utf8'));
if (kind !== body.kind || version !== body.apiVersion) {
throw new error_1.VerificationError(TLOG_MISMATCH_ERROR_MSG);
}
switch (body.kind) {
case 'intoto':
verifyIntotoTLogBody(body, bundle);
break;
case 'hashedrekord':
verifyHashedRekordTLogBody(body, bundle);
break;
default:
throw new Error('Unsupported bundle type');
throw new error_1.UnsupportedVersionError(`unsupported kind in tlog entry: ${kind}`);
}
}
function toPublicKey(verificationMaterial) {
var _a;
switch ((_a = verificationMaterial === null || verificationMaterial === void 0 ? void 0 : verificationMaterial.content) === null || _a === void 0 ? void 0 : _a.$case) {
case 'x509CertificateChain': {
const der = verificationMaterial.content.x509CertificateChain.certificates[0];
return util_1.pem.fromDER(der.rawBytes);
}
case 'publicKey':
// TODO: How to handle this?
// eslint-disable-next-line no-fallthrough
// Compare the given intoto tlog entry to the given bundle
function verifyIntotoTLogBody(tlogEntry, bundle) {
var _a, _b;
if (((_a = bundle.content) === null || _a === void 0 ? void 0 : _a.$case) !== 'dsseEnvelope') {
throw new error_1.UnsupportedVersionError(`unsupported bundle content: ${((_b = bundle.content) === null || _b === void 0 ? void 0 : _b.$case) || 'unknown'}`);
}
const dsse = bundle.content.dsseEnvelope;
switch (tlogEntry.apiVersion) {
case '0.0.2':
verifyIntoto002TLogBody(tlogEntry, dsse);
break;
default:
throw new Error('No certificate found in bundle');
throw new error_1.UnsupportedVersionError(`unsupported intoto version: ${tlogEntry.apiVersion}`);
}
}
// Recreates a Rekor "hashedrekord" entry from the bundle.
function toMessageSignatureVerificationBody(messageSignature, certificate) {
var _a;
const digest = ((_a = messageSignature.messageDigest) === null || _a === void 0 ? void 0 : _a.digest) || Buffer.from('');
const sig = messageSignature.signature;
const sigMaterial = {
signature: sig,
certificates: [certificate],
key: undefined,
};
return (0, format_1.toProposedHashedRekordEntry)(digest, sigMaterial);
// Compare the given hashedrekord tlog entry to the given bundle
function verifyHashedRekordTLogBody(tlogEntry, bundle) {
var _a, _b;
if (((_a = bundle.content) === null || _a === void 0 ? void 0 : _a.$case) !== 'messageSignature') {
throw new error_1.UnsupportedVersionError(`unsupported bundle content: ${((_b = bundle.content) === null || _b === void 0 ? void 0 : _b.$case) || 'unknown'}`);
}
const messageSignature = bundle.content.messageSignature;
switch (tlogEntry.apiVersion) {
case '0.0.1':
verifyHashedrekor001TLogBody(tlogEntry, messageSignature);
break;
default:
throw new error_1.UnsupportedVersionError(`unsupported hashedrekord version: ${tlogEntry.apiVersion}`);
}
}
// Recreates a Rekor "intoto" entry from the bundle.
function toDSSEVerificationBody(dsseEnvelope, certificate) {
// Compare the given intoto v0.0.2 tlog entry to the given DSSE envelope.
function verifyIntoto002TLogBody(tlogEntry, dsse) {
var _a, _b;
const sig = dsseEnvelope.signatures[0].sig;
const sigMaterial = {
signature: sig,
certificates: [certificate],
key: undefined,
};
const body = (0, format_1.toProposedIntotoEntry)(dsseEnvelope, sigMaterial);
// When Rekor saves the entry it removes the payload from the envelope
if (body.apiVersion === '0.0.2') {
(_b = (_a = body.spec.content) === null || _a === void 0 ? void 0 : _a.envelope) === null || _b === void 0 ? true : delete _b.payload;
// Collect all of the signatures from the DSSE envelope
// Turns them into base64-encoded strings for comparison
const dsseSigs = dsse.signatures.map((signature) => signature.sig.toString('base64'));
// Collect all of the signatures from the tlog entry
// Remember that tlog signastures are double base64-encoded
const tlogSigs = (_a = tlogEntry.spec.content.envelope) === null || _a === void 0 ? void 0 : _a.signatures.map((signature) => (signature.sig ? util_1.encoding.base64Decode(signature.sig) : ''));
// Ensure the bundle's DSSE and the tlog entry contain the same number of signatures
if (dsseSigs.length !== (tlogSigs === null || tlogSigs === void 0 ? void 0 : tlogSigs.length)) {
throw new error_1.VerificationError(TLOG_MISMATCH_ERROR_MSG);
}
return body;
// Ensure that every signature in the bundle's DSSE is present in the tlog entry
if (!dsseSigs.every((dsseSig) => tlogSigs.includes(dsseSig))) {
throw new error_1.VerificationError(TLOG_MISMATCH_ERROR_MSG);
}
// Ensure the digest of the bundle's DSSE payload matches the digest in the
// tlog entry
const dssePayloadHash = util_1.crypto.hash(dsse.payload).toString('hex');
if (dssePayloadHash !== ((_b = tlogEntry.spec.content.payloadHash) === null || _b === void 0 ? void 0 : _b.value)) {
throw new error_1.VerificationError(TLOG_MISMATCH_ERROR_MSG);
}
}
// Compare the given hashedrekord v0.0.1 tlog entry to the given message
// signature
function verifyHashedrekor001TLogBody(tlogEntry, messageSignature) {
var _a, _b;
// Ensure that the bundles message signature matches the tlog entry
const msgSig = messageSignature.signature.toString('base64');
const tlogSig = tlogEntry.spec.signature.content;
if (msgSig !== tlogSig) {
throw new error_1.VerificationError(TLOG_MISMATCH_ERROR_MSG);
}
// Ensure that the bundle's message digest matches the tlog entry
const msgDigest = (_a = messageSignature.messageDigest) === null || _a === void 0 ? void 0 : _a.digest.toString('hex');
const tlogDigest = (_b = tlogEntry.spec.data.hash) === null || _b === void 0 ? void 0 : _b.value;
if (msgDigest !== tlogDigest) {
throw new error_1.VerificationError(TLOG_MISMATCH_ERROR_MSG);
}
}
// Returns a properly formatted "VerificationPayload" for one of the
// transaction log entires in the given bundle which can be used for SET
// verification.
function toVerificationPayload(entry) {
// Rekor metadata
const { integratedTime, logIndex, logId, canonicalizedBody } = entry;
if (!logId) {
throw new error_1.InvalidBundleError('no logId found in bundle');
}
return {
body: canonicalizedBody.toString('base64'),
integratedTime: Number(integratedTime),
logIndex: Number(logIndex),
logID: logId.keyId.toString('hex'),
};
}

@@ -109,2 +109,11 @@ /// <reference types="node" />

inclusionProof: InclusionProof | undefined;
/**
* The canonicalized Rekor entry body, used for SET verification. This
* is the same as the body returned by Rekor. It's included here for
* cases where the client cannot deterministically reconstruct the
* bundle from the other fields. Clients MUST verify that the signature
* referenced in the canonicalized_body matches the signature provided
* in the bundle content.
*/
canonicalizedBody: Buffer;
}

@@ -111,0 +120,0 @@ export declare const KindVersion: {

@@ -105,2 +105,3 @@ "use strict";

inclusionProof: undefined,
canonicalizedBody: Buffer.alloc(0),
};

@@ -117,2 +118,5 @@ }

inclusionProof: isSet(object.inclusionProof) ? exports.InclusionProof.fromJSON(object.inclusionProof) : undefined,
canonicalizedBody: isSet(object.canonicalizedBody)
? Buffer.from(bytesFromBase64(object.canonicalizedBody))
: Buffer.alloc(0),
};

@@ -131,2 +135,4 @@ },

(obj.inclusionProof = message.inclusionProof ? exports.InclusionProof.toJSON(message.inclusionProof) : undefined);
message.canonicalizedBody !== undefined &&
(obj.canonicalizedBody = base64FromBytes(message.canonicalizedBody !== undefined ? message.canonicalizedBody : Buffer.alloc(0)));
return obj;

@@ -133,0 +139,0 @@ },

@@ -10,2 +10,3 @@ /// <reference types="node" />

export * from './__generated__/sigstore_common';
export { TransparencyLogEntry } from './__generated__/sigstore_rekor';
export declare const bundleToJSON: (message: Bundle) => unknown;

@@ -12,0 +13,0 @@ export declare const bundleFromJSON: (object: any) => Bundle;

@@ -17,3 +17,3 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.bundle = exports.envelopeFromJSON = exports.envelopeToJSON = exports.bundleFromJSON = exports.bundleToJSON = void 0;
exports.bundle = exports.envelopeFromJSON = exports.envelopeToJSON = exports.bundleFromJSON = exports.bundleToJSON = exports.TransparencyLogEntry = void 0;
const util_1 = require("../../util");

@@ -27,2 +27,4 @@ const envelope_1 = require("./__generated__/envelope");

__exportStar(require("./__generated__/sigstore_common"), exports);
var sigstore_rekor_1 = require("./__generated__/sigstore_rekor");
Object.defineProperty(exports, "TransparencyLogEntry", { enumerable: true, get: function () { return sigstore_rekor_1.TransparencyLogEntry; } });
exports.bundleToJSON = sigstore_bundle_1.Bundle.toJSON;

@@ -89,2 +91,3 @@ exports.bundleFromJSON = sigstore_bundle_1.Bundle.fromJSON;

inclusionProof: undefined,
canonicalizedBody: Buffer.from(entry.body, 'base64'),
};

@@ -91,0 +94,0 @@ }

@@ -25,2 +25,3 @@ import { OneOf } from '../utility';

} | undefined;
canonicalizedBody: string;
}[];

@@ -27,0 +28,0 @@ timestampVerificationData: {

export * as crypto from './crypto';
export * as dsse from './dsse';
export * as encoding from './encoding';
export * as json from './json';
export * as oidc from './oidc';

@@ -8,2 +9,2 @@ export * as pem from './pem';

export * as ua from './ua';
export * as json from './json';
export * as x509 from './x509';

@@ -26,3 +26,3 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.json = exports.ua = exports.promise = exports.pem = exports.oidc = exports.encoding = exports.dsse = exports.crypto = void 0;
exports.x509 = exports.ua = exports.promise = exports.pem = exports.oidc = exports.json = exports.encoding = exports.dsse = exports.crypto = void 0;
/*

@@ -46,2 +46,3 @@ Copyright 2022 The Sigstore Authors.

exports.encoding = __importStar(require("./encoding"));
exports.json = __importStar(require("./json"));
exports.oidc = __importStar(require("./oidc"));

@@ -51,2 +52,2 @@ exports.pem = __importStar(require("./pem"));

exports.ua = __importStar(require("./ua"));
exports.json = __importStar(require("./json"));
exports.x509 = __importStar(require("./x509"));

@@ -6,5 +6,7 @@ /// <reference types="node" />

import { Bundle } from './types/bundle';
export declare type GetPublicKeyFunc = (keyId: string) => Promise<string | undefined>;
export interface VerifyOptions {
tlog: TLog;
tlogKeys: Record<string, KeyObject>;
getPublicKey?: GetPublicKeyFunc;
}

@@ -14,4 +16,6 @@ export declare class Verifier {

private tlogKeys;
private getExternalPublicKey;
constructor(options: VerifyOptions);
verifyOffline(bundle: Bundle, data?: Buffer): void;
verifyOffline(bundle: Bundle, data?: Buffer): Promise<void>;
getPublicKey(bundle: Bundle): Promise<string>;
}

@@ -11,7 +11,28 @@ "use strict";

this.tlogKeys = options.tlogKeys;
this.getExternalPublicKey =
options.getPublicKey || (() => Promise.resolve(undefined));
}
verifyOffline(bundle, data) {
verifyArtifactSignature(bundle, data);
(0, verify_1.verifyTLogSET)(bundle, this.tlogKeys);
async verifyOffline(bundle, data) {
const publicKey = await this.getPublicKey(bundle);
verifyArtifactSignature(bundle, publicKey, data);
(0, verify_1.verifyTLogEntries)(bundle, this.tlogKeys);
}
async getPublicKey(bundle) {
var _a, _b;
let publicKey;
switch ((_b = (_a = bundle.verificationMaterial) === null || _a === void 0 ? void 0 : _a.content) === null || _b === void 0 ? void 0 : _b.$case) {
case 'x509CertificateChain':
publicKey = getSigningCertificate(bundle.verificationMaterial.content.x509CertificateChain);
break;
case 'publicKey':
publicKey = await this.getExternalPublicKey(bundle.verificationMaterial.content.publicKey.hint);
break;
default:
throw new error_1.InvalidBundleError('no verification material found');
}
if (!publicKey) {
throw new error_1.VerificationError('no public key found for signature verification');
}
return publicKey;
}
}

@@ -21,3 +42,3 @@ exports.Verifier = Verifier;

// content and delegates to the appropriate signature verification function.
function verifyArtifactSignature(bundle, data) {
function verifyArtifactSignature(bundle, publicKey, data) {
var _a;

@@ -27,11 +48,11 @@ switch ((_a = bundle.content) === null || _a === void 0 ? void 0 : _a.$case) {

if (!data) {
throw new error_1.VerificationError('No data provided for message signature verification');
throw new error_1.VerificationError('no data provided for message signature verification');
}
verifyMessageSignature(bundle, data);
verifyMessageSignature(bundle.content.messageSignature, publicKey, data);
break;
case 'dsseEnvelope':
verifyDSSESignature(bundle);
verifyDSSESignature(bundle.content.dsseEnvelope, publicKey);
break;
default:
throw new error_1.VerificationError('Bundle is invalid');
throw new error_1.InvalidBundleError('no content found');
}

@@ -41,13 +62,7 @@ }

// Verifies the signature found in the bundle against the provided data.
function verifyMessageSignature(bundle, data) {
var _a;
if (((_a = bundle.content) === null || _a === void 0 ? void 0 : _a.$case) !== 'messageSignature') {
throw new error_1.VerificationError('No message signature found in bundle');
}
function verifyMessageSignature(messageSignature, publicKey, data) {
// Extract signature for message
const signature = bundle.content.messageSignature.signature;
// Get signing certificate containing public key
const publicKey = getSigningCertificate(bundle);
const signature = messageSignature.signature;
if (!util_1.crypto.verifyBlob(data, publicKey, signature)) {
throw new error_1.VerificationError('Artifact signature verification failed');
throw new error_1.VerificationError('artifact signature verification failed');
}

@@ -58,21 +73,14 @@ }

// signature in the envelope.
function verifyDSSESignature(bundle) {
var _a;
if (((_a = bundle.content) === null || _a === void 0 ? void 0 : _a.$case) !== 'dsseEnvelope') {
throw new error_1.VerificationError('Bundle is not a DSSE envelope');
}
function verifyDSSESignature(envelope, publicKey) {
// Construct payload over which the signature was originally created
const payloadType = bundle.content.dsseEnvelope.payloadType;
const payload = bundle.content.dsseEnvelope.payload;
const { payloadType, payload } = envelope;
const data = util_1.dsse.preAuthEncoding(payloadType, payload);
// Extract signature from DSSE envelope
if (bundle.content.dsseEnvelope.signatures.length < 1) {
throw new error_1.VerificationError('No signatures found in DSSE envelope');
if (envelope.signatures.length < 1) {
throw new error_1.InvalidBundleError('no signatures found in DSSE envelope');
}
// TODO: Support multiple signatures
const signature = bundle.content.dsseEnvelope.signatures[0].sig;
// Get signing certificate containing public key
const publicKey = getSigningCertificate(bundle);
// Only support a single signature in DSSE
const signature = envelope.signatures[0].sig;
if (!util_1.crypto.verifyBlob(data, publicKey, signature)) {
throw new error_1.VerificationError('Artifact signature verification failed');
throw new error_1.VerificationError('artifact signature verification failed');
}

@@ -82,12 +90,5 @@ }

// PEM-encoded string.
function getSigningCertificate(bundle) {
var _a, _b;
if (((_b = (_a = bundle.verificationMaterial) === null || _a === void 0 ? void 0 : _a.content) === null || _b === void 0 ? void 0 : _b.$case) !== 'x509CertificateChain') {
throw new error_1.VerificationError('No certificate found in bundle');
}
const signingCert = bundle.verificationMaterial.content.x509CertificateChain.certificates[0];
if (!signingCert) {
throw new error_1.VerificationError('No certificate found in bundle');
}
return util_1.pem.fromDER(signingCert.rawBytes);
function getSigningCertificate(chain) {
const signingCert = chain.certificates[0];
return signingCert ? util_1.pem.fromDER(signingCert.rawBytes) : undefined;
}
{
"name": "sigstore",
"version": "0.0.1-alpha.4",
"version": "0.0.1-alpha.5",
"description": "code-signing for npm packages",

@@ -54,3 +54,6 @@ "main": "dist/index.js",

"make-fetch-happen": "^11.0.1"
},
"engines": {
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
}
}

@@ -5,3 +5,5 @@ # sigstore-js

A tool for signing and verifying npm packages.
A tool for signing and verifying signatures using JavaScript.
One of the intended uses is to sign and verify npm packages
but it can be used to sign and verify any file.

@@ -8,0 +10,0 @@ ## Features

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc