UNPKG

ctutils

Version:

Utilities for interacting with Certificate Transparency logs

238 lines (205 loc) 11.2 kB
/** * Certificate Transparency Utilities * Test SignedTreeHead * * By Fotis Loukos <me@fotisl.com> */ require('babel-polyfill'); const assert = require('assert'); const pvutils = require('pvutils'); const CTUtils = require('..'); const WebCrypto = require('node-webcrypto-ossl'); const webcrypto = new WebCrypto(); CTUtils.setWebCrypto(webcrypto); describe('SignedTreeHead', () => { describe('#verify()', () => { it('should verify correct ECDSA SignedTreeHead with public key', () => { const rootHash = pvutils.stringToArrayBuffer(pvutils.fromBase64( '7IXxX5gNLhKS4vANtkO0gPAqx9YRra17IJfzMJM2AiQ=')); const signature = pvutils.stringToArrayBuffer(pvutils.fromBase64( 'BAMARjBEAiBktm+l47z01OLaAAwUtDGNr+xzjJJRG5aNBcx3fBxxBQIgTlC/Ck3cSLu' + 'K23N+/7BQxv4xfQbF1RH7pG/6S3N6Z4U=')); const pubKey = pvutils.stringToArrayBuffer(pvutils.fromBase64( 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE0gBVBa3VR7QZu82V+ynXWD14JM3ORp3' + '7MtRxTmACJV5ZPtfUA7htQ2hofuigZQs+bnFZkje+qejxoyvk2Q1VaA==')); const sth = new CTUtils.SignedTreeHead(170761442, 1526202484196, rootHash, signature, CTUtils.Version.v1); return sth.verify(pubKey).then(res => { assert.equal(res, true, 'Cannot verify'); }); }); it('should verify correct ECDSA SignedTreeHead with CTLog', () => { const rootHash = pvutils.stringToArrayBuffer(pvutils.fromBase64( '7IXxX5gNLhKS4vANtkO0gPAqx9YRra17IJfzMJM2AiQ=')); const signature = pvutils.stringToArrayBuffer(pvutils.fromBase64( 'BAMARjBEAiBktm+l47z01OLaAAwUtDGNr+xzjJJRG5aNBcx3fBxxBQIgTlC/Ck3cSLu' + 'K23N+/7BQxv4xfQbF1RH7pG/6S3N6Z4U=')); const pubKey = pvutils.stringToArrayBuffer(pvutils.fromBase64( 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE0gBVBa3VR7QZu82V+ynXWD14JM3ORp3' + '7MtRxTmACJV5ZPtfUA7htQ2hofuigZQs+bnFZkje+qejxoyvk2Q1VaA==')); const log = new CTUtils.CTLog('ct.googleapis.com/pilot/', pubKey); const sth = new CTUtils.SignedTreeHead(170761442, 1526202484196, rootHash, signature, CTUtils.Version.v1); return sth.verify(log).then(res => { assert.equal(res, true, 'Cannot verify'); }); }); it('should detect incorrect ECDSA SignedTreeHead', () => { const rootHash = pvutils.stringToArrayBuffer(pvutils.fromBase64( '7IXxX5gNLhKS4vANtkO0gPAqx9YRra17IJfzMJM2AiQ=')); const signature = pvutils.stringToArrayBuffer(pvutils.fromBase64( 'BAMARjBEAiBktm+l47z01OLaAAwUtDGNr+xzjJJRG5aNBcx3fBxxBQIgTlC/Ck3cSLu' + 'K23N+/7BQxv4xfQbF1RH7pG/6S3N6Z4U=')); const pubKey = pvutils.stringToArrayBuffer(pvutils.fromBase64( 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE0gBVBa3VR7QZu82V+ynXWD14JM3ORp3' + '7MtRxTmACJV5ZPtfUA7htQ2hofuigZQs+bnFZkje+qejxoyvk2Q1VaA==')); const verSignature = new Uint8Array(signature); verSignature[5]++; const sth = new CTUtils.SignedTreeHead(170761442, 1526202484196, rootHash, signature, CTUtils.Version.v1); return sth.verify(pubKey).then(res => { assert.equal(res, false, 'Cannot detect'); }); }); it('should verify correct RSA SignedTreeHead', () => { const rootHash = pvutils.stringToArrayBuffer(pvutils.fromBase64( 'I7PzqT8cEPjlfgOx3/2VxnuO5BTIJ6Zf8OM8DAwGhuM=')); const signature = pvutils.stringToArrayBuffer(pvutils.fromBase64( 'BAEBAAgJjfMWJ0agR0VCpB1v8UJs3X8H3dPU8C0NmUMtMAdAm27tgiDcpDECHCMrJbI' + 'Iy7v+y1p4zVGC6eWf1Tew+W+O32WinshHb9th7lLNlQ5yJUKW5UtMTJxW/BiFpHO75+' + 'WXsajb4EyTPkoJ1M2qxDX/cK/hSb2ar0W7G9weRaw7WetwEAG7pv2j/tnUUGXHWfnNk' + 'g6f40GkwSaGfY9Xw9gaZDeUawvS8T61qODsaZprWDsBAWaClaaelrmlx0kkZBnMP/LK' + 'KSlywrTNEt3Ow1oKBqT3nL5A2fTPoRfsF+1OGyy2iokX2pI1ZLBRS4v4rqMce/dgzXx' + 'rS6OUUINHfLA=')); const pubKey = pvutils.stringToArrayBuffer(pvutils.fromBase64( 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAolpIHxdSlTXLo1s6H1OCdpS' + 'j/4DyHDc8wLG9wVmLqy1lk9fz4ATVmm+/1iN2Nk8jmctUKK2MFUtlWXZBSpym97M7fr' + 'GlSaQXUWyA3CqQUEuIJOmlEjKTBEiQAvpfDjCHjlV2Be4qTM6jamkJbiWtgnYPhJL6O' + 'NaGTiSPm7Byy57iaz/hbckldSOIoRhYBiMzeNoA0DiRZ9KmfSeXZ1rB8y8X5urSW+iB' + 'zf2SaOfzBvDpcoTuAaWx2DPazoOl28fP1hZ+kHUYvxbcMjttjauCFx+JII0dmuZNIwj' + 'feG/GBb9frpSX219k1O4Wi6OEbHEr8at/XQ0y7gTikOxBn/s5wQIDAQAB')); const sth = new CTUtils.SignedTreeHead(90161, 1488320541206, rootHash, signature, CTUtils.Version.v1); return sth.verify(pubKey).then(res => { assert.equal(res, true, 'Cannot verify'); }); }); it('should detect incorrect RSA SignedTreeHead', () => { const rootHash = pvutils.stringToArrayBuffer(pvutils.fromBase64( 'I7PzqT8cEPjlfgOx3/2VxnuO5BTIJ6Zf8OM8DAwGhuM=')); const signature = pvutils.stringToArrayBuffer(pvutils.fromBase64( 'BAEBAAgJjfMWJ0agR0VCpB1v8UJs3X8H3dPU8C0NmUMtMAdAm27tgiDcpDECHCMrJbI' + 'Iy7v+y1p4zVGC6eWf1Tew+W+O32WinshHb9th7lLNlQ5yJUKW5UtMTJxW/BiFpHO75+' + 'WXsajb4EyTPkoJ1M2qxDX/cK/hSb2ar0W7G9weRaw7WetwEAG7pv2j/tnUUGXHWfnNk' + 'g6f40GkwSaGfY9Xw9gaZDeUawvS8T61qODsaZprWDsBAWaClaaelrmlx0kkZBnMP/LK' + 'KSlywrTNEt3Ow1oKBqT3nL5A2fTPoRfsF+1OGyy2iokX2pI1ZLBRS4v4rqMce/dgzXx' + 'rS6OUUINHfLA=')); const pubKey = pvutils.stringToArrayBuffer(pvutils.fromBase64( 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAolpIHxdSlTXLo1s6H1OCdpS' + 'j/4DyHDc8wLG9wVmLqy1lk9fz4ATVmm+/1iN2Nk8jmctUKK2MFUtlWXZBSpym97M7fr' + 'GlSaQXUWyA3CqQUEuIJOmlEjKTBEiQAvpfDjCHjlV2Be4qTM6jamkJbiWtgnYPhJL6O' + 'NaGTiSPm7Byy57iaz/hbckldSOIoRhYBiMzeNoA0DiRZ9KmfSeXZ1rB8y8X5urSW+iB' + 'zf2SaOfzBvDpcoTuAaWx2DPazoOl28fP1hZ+kHUYvxbcMjttjauCFx+JII0dmuZNIwj' + 'feG/GBb9frpSX219k1O4Wi6OEbHEr8at/XQ0y7gTikOxBn/s5wQIDAQAB')); const verSignature = new Uint8Array(signature); verSignature[5]++; const sth = new CTUtils.SignedTreeHead(90161, 1488320541206, rootHash, signature, CTUtils.Version.v1); return sth.verify(pubKey).then(res => { assert.equal(res, false, 'Cannot detect'); }); }); }); describe('#verifyConsistency()', () => { it('should verify consistent STHs', () => { const firstRootHash = pvutils.stringToArrayBuffer(pvutils.fromBase64( '6S3D8D5Q8NV5tK3CoG8TK+6rSEG7cXpgpVWqMQaIQJ8=')); const firstSignature = pvutils.stringToArrayBuffer(pvutils.fromBase64( 'BAMARjBEAiBz2MSIUxbtCarz9gdxHqGDxpKCbjL7T5h6DEIhtGKDAQIgQs/TZ96jUsf' + 'FX5TtkmtxXz4+vnpY4rW/VgCiCx67Yn4=')); const secondRootHash = pvutils.stringToArrayBuffer(pvutils.fromBase64( 'mUlAb0rslEHouTTTFyDP4vQO/eIRqE8jInH8mucA39M=')); const secondSignature = pvutils.stringToArrayBuffer(pvutils.fromBase64( 'BAMARzBFAiEA0EBSQV04N21UW5OOYz/6uiMlmtoPzjaTXkx8mJP7O94CIHrQJj8izOX' + 'Uwm1JEzxN1ttR+tB3I+g48BPFkf81+NER')); const first = new CTUtils.SignedTreeHead(16444754, 1526367328650, firstRootHash, firstSignature, CTUtils.Version.v1); const second = new CTUtils.SignedTreeHead(16447636, 1526370936098, secondRootHash, secondSignature, CTUtils.Version.v1); const proofs = []; const b64Proofs = [ 'GfgUCq5pXIuh73fnDJUb0S64a1slZtXg8zlzK/fUpZI=', 'EYq9SFQp8MoARFevnAdygE2Tu195PN7CxJchGSfpCfM=', 'HH4j+gtRTV3rHyX1YNJI3t02ymealM9y6pG+Lik3Gg0=', 'gbLLA1hCLR9fLDnlLvBvRGYO0yImF7B67WbSAvqr74A=', 'oPDj7RRLmgqiIDeU5nc01vxlozz71zwrPzTIxjB9fSg=', 'aYhCIv6Debl1joA5IPvUkEcxXYJxGiwGFaoNlZkse7o=', 'nelm9OnVACDlCaiVHCunBGp9YVkhaURfmo1AnIzSs6o=', 'vXEfahB7EyEErnFVVF+tdRyVG6V+dPxqwWJk2ov0OaQ=', 'CU1mwi8t2zxJs/yGD6mbl9m7BQ/WKWCobyqrRUey6OU=', 'zdcqHoTxpDf93hT5b12pNEOWptRblwwvpQ02Ec7+Vaw=', '84yTmprYU9gaz3WmRBh4rxwkwgNcFw9GqPRvpsxGRtY=', 'J3sqEFzMu4+hHRcGSQDduT2uRHPBuASWPOzhRx4uH6k=', 'bAaUza+ovsYOjq1x5iivqRfKNGPbqIGhPrYDDxVONKY=', 's3kKZn0XeyLdqmPO3GIXy+7NfAJHUWkSdOJoBca+RaI=', 'OwMsUuW6n89cgBN5lXcc0n4b56a+Cf9qbEMqswwQZN8=', '7JeM6ZM735FiP9Oaz/uatrdWWLTqKniSeioOzuVUCtg=', 'sbmlvlUXeq/JapoVdVCcp3ievD6IlZrut/Z9yqh76Z8=', 'SBv3+jTnmLJ0ssGawyrik3r8Q1XvfmRoKZ1XRXV6PDU=', 'kD1mHZzJzODGPRwryE4Q2F/FjhHDe88eQ3PkT7nh2Rw=', 'D8da4qJEsYH/MvQVRIzhCqCdbUxJqMG/LSgKvvKQ94A=', 'X0H/hecm8dBP9TmBCrYOIc0T+o53Po+TBmLsaz2A32w=', '4BmXk7bMyQWV3cj14p/4jsZnob53XEULsISzf155AaI=' ]; b64Proofs.forEach(bp => { proofs.push(pvutils.stringToArrayBuffer(pvutils.fromBase64(bp))); }); return first.verifyConsistency(second, proofs).then(res => { assert.equal(res, true, 'Cannot verify'); }); }); it('should detect inconsistent STHs', () => { /* Venafi log inconsistency */ const firstRootHash = pvutils.stringToArrayBuffer(pvutils.fromBase64( 'I7PzqT8cEPjlfgOx3/2VxnuO5BTIJ6Zf8OM8DAwGhuM=')); const firstSignature = pvutils.stringToArrayBuffer(pvutils.fromBase64( 'BAEBAAgJjfMWJ0agR0VCpB1v8UJs3X8H3dPU8C0NmUMtMAdAm27tgiDcpDECHCMrJbI' + 'Iy7v+y1p4zVGC6eWf1Tew+W+O32WinshHb9th7lLNlQ5yJUKW5UtMTJxW/BiFpHO75+' + 'WXsajb4EyTPkoJ1M2qxDX/cK/hSb2ar0W7G9weRaw7WetwEAG7pv2j/tnUUGXHWfnNk' + 'g6f40GkwSaGfY9Xw9gaZDeUawvS8T61qODsaZprWDsBAWaClaaelrmlx0kkZBnMP/LK' + 'KSlywrTNEt3Ow1oKBqT3nL5A2fTPoRfsF+1OGyy2iokX2pI1ZLBRS4v4rqMce/dgzXx' + 'rS6OUUINHfLA=')); const secondRootHash = pvutils.stringToArrayBuffer(pvutils.fromBase64( 'sMnqsYxLYyKdF7QNqplWgnIJk6WBsuqlEGo0aNHHhRg=')); const secondSignature = pvutils.stringToArrayBuffer(pvutils.fromBase64( 'BAEBAIXJw+INMcxEzrsW3+tzgxiE2jP8sJZN5HYwO3MmuFHy5t57lJqPADYEFBIfx7c' + 'EEGyp0RQLb6Wonvkq4xhsANt0xXCQQw1STxRKixnaYtSnEkoVJfWXPAVyjUqFPx+ryO' + 'HtdocMGlf60rt4UmGK0rhy9XTCrktYFkzG9ZPrGujGDvXIeBnIaarbU0L5g224rsdLv' + 'DXwpRopHpHinomsc5W+ReA+eQ38WGBHkz33e/+YPJQGd/L3EaDN3da0VIEYNHY5AGW/' + 'Yq7rU6cD+dHH9mL1OK971/HZ362aEnBBZ47zi/1OzANeKdT1tyB+db7VpXhScJxw1o0' + 'G3T0V0P+lM4o=')); const first = new CTUtils.SignedTreeHead(90161, 1488320541206, firstRootHash, firstSignature, CTUtils.Version.v1); const second = new CTUtils.SignedTreeHead(90167, 1488321064440, secondRootHash, secondSignature, CTUtils.Version.v1); const proofs = []; const b64proofs = [ 'r+r7qrYh4i9lWa1nzVO86nj+9c6BGZq5i36IRzgPGl4=', 'NPLfppxk5a1xQZb/tmCK3oJ/WFflOaxx4pNE49Tf+8Y=', 'U0IGCc5N616P/zKPQVkFZkYdRoSBmLipCgspE0vNLeE=', 'kZiqCHdVXWXLAmFtPPm6tNUBm3ciQY7KTkBIPdPyP50=', 'im9E++S7hURbeazY1bHGqxx6/5zYmDmpLhCU3lAvGOM=', 'VH8nj3DKzwv9v3bcQeDKjw4a0H+GbIm1SIxU0z3J/1E=', '2eQpspAlOaHniWW6exNICgPfge2u0BHXAU0bJoCxy+c=', 'jsEyi+238H+/SNiDNmoNeGTPeMkBEeM55WNKuuPrfeY=', 'rcxt0aKSfv5MGCDJSwt6WDZffq9Nmp4SpQm5Xr376Lo=' ]; b64proofs.forEach(bp => { proofs.push(pvutils.stringToArrayBuffer(pvutils.fromBase64(bp))); }); return first.verifyConsistency(second, proofs).then(res => { assert.equal(res, false, 'Cannot detect'); }); }); }); });