mirror of
https://github.com/openpgpjs/openpgpjs.git
synced 2025-03-30 15:08:32 +00:00

Parsing of v5 keys, v5 signatures and AEAD-encrypted data packets now requires turning on the corresponding config flag. The affected entities are non-standard, and in the crypto-refresh RFC they have been superseded by v6 keys, v6 signatures and SEIPDv2 encrypted data, respectively. However, generation of v5 entities was supported behind config flag in OpenPGP.js v5, and some other libraries, hence parsing them might be necessary in some cases.
2520 lines
128 KiB
JavaScript
2520 lines
128 KiB
JavaScript
/* eslint-disable max-lines */
|
|
/* globals tryTests, loadStreamsPolyfill */
|
|
import * as stream from '@openpgp/web-stream-tools';
|
|
import { use as chaiUse, expect } from 'chai';
|
|
import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/newline-after-import
|
|
chaiUse(chaiAsPromised);
|
|
|
|
import openpgp from '../initOpenpgp.js';
|
|
|
|
import util from '../../src/util.js';
|
|
|
|
export default () => describe('Signature', function() {
|
|
const priv_key_arm1 =
|
|
['-----BEGIN PGP PRIVATE KEY BLOCK-----',
|
|
'Version: GnuPG v1.4.11 (GNU/Linux)',
|
|
'',
|
|
'lQHhBFERnrMRBADmM0hIfkI3yosjgbWo9v0Lnr3CCE+8KsMszgVS+hBu0XfGraKm',
|
|
'ivcA2aaJimHqVYOP7gEnwFAxHBBpeTJcu5wzCFyJwEYqVeS3nnaIhBPplSF14Duf',
|
|
'i6bB9RV7KxVAg6aunmM2tAutqC+a0y2rDaf7jkJoZ9gWJe2zI+vraD6fiwCgxvHo',
|
|
'3IgULB9RqIqpLoMgXfcjC+cD/1jeJlKRm+n71ryYwT/ECKsspFz7S36z6q3XyS8Q',
|
|
'QfrsUz2p1fbFicvJwIOJ8B20J/N2/nit4P0gBUTUxv3QEa7XCM/56/xrGkyBzscW',
|
|
'AzBoy/AK9K7GN6z13RozuAS60F1xO7MQc6Yi2VU3eASDQEKiyL/Ubf/s/rkZ+sGj',
|
|
'yJizBACtwCbQzA+z9XBZNUat5NPgcZz5Qeh1nwF9Nxnr6pyBv7tkrLh/3gxRGHqG',
|
|
'063dMbUk8pmUcJzBUyRsNiIPDoEUsLjY5zmZZmp/waAhpREsnK29WLCbqLdpUors',
|
|
'c1JJBsObkA1IM8TZY8YUmvsMEvBLCCanuKpclZZXqeRAeOHJ0v4DAwK8WfuTe5B+',
|
|
'M2BOOeZbN8BpfiA1l//fMMHLRS3UvbLBv4P1+4SyvhyYTR7M76Q0xPc03MFOWHL+',
|
|
'S9VumbQWVGVzdDIgPHRlc3QyQHRlc3QuY29tPohiBBMRAgAiBQJREZ6zAhsDBgsJ',
|
|
'CAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRARJ5QDyxae+MXNAKCzWSDR3tMrTrDb',
|
|
'TAri73N1Xb3j1ACfSl9y+SAah2q7GvmiR1+6+/ekqJGdAVgEURGesxAEANlpMZjW',
|
|
'33jMxlKHDdyRFXtKOq8RreXhq00plorHbgz9zFEWm4VF53+E/KGnmHGyY5Cy8TKy',
|
|
'ZjaueZZ9XuG0huZg5If68irFfNZtxdA26jv8//PdZ0Uj+X6J3RVa2peMLDDswTYL',
|
|
'OL1ZO1fxdtDD40fdAiIZ1QyjwEG0APtz41EfAAMFBAC5/dtgBBPtHe8UjDBaUe4n',
|
|
'NzHuUBBp6XE+H7eqHNFCuZAJ7yqJLGVHNIaQR419cNy08/OO/+YUQ7rg78LxjFiv',
|
|
'CH7IzhfU+6yvELSbgRMicY6EnAP2GT+b1+MtFNa3lBGtBHcJla52c2rTAHthYZWk',
|
|
'fT5R5DnJuQ2cJHBMS9HWyP4DAwK8WfuTe5B+M2C7a/YJSUv6SexdGCaiaTcAm6g/',
|
|
'PvA6hw/FLzIEP67QcQSSTmhftQIwnddt4S4MyJJH3U4fJaFfYQ1zCniYJohJBBgR',
|
|
'AgAJBQJREZ6zAhsMAAoJEBEnlAPLFp74QbMAn3V4857xwnO9/+vzIVnL93W3k0/8',
|
|
'AKC8omYPPomN1E/UJFfXdLDIMi5LoA==',
|
|
'=LSrW',
|
|
'-----END PGP PRIVATE KEY BLOCK-----'].join('\n');
|
|
|
|
const pub_key_arm1 =
|
|
['-----BEGIN PGP PUBLIC KEY BLOCK-----',
|
|
'Version: GnuPG v1.4.11 (GNU/Linux)',
|
|
'',
|
|
'mQGiBFERlw4RBAD6Bmcf2w1dtUmtCLkdxeqZLArk3vYoQAjdibxA3gXVyur7fsWb',
|
|
'ro0jVbBHqOCtC6jDxE2l52NP9+tTlWeVMaqqNvUE47LSaPq2DGI8Wx1Rj6bF3mTs',
|
|
'obYEwhGbGh/MhJnME9AHODarvk8AZbzo0+k1EwrBWF6dTUBPfqO7rGU2ewCg80WV',
|
|
'x5pt3evj8rRK3jQ8SMKTNRsD/1PhTdxdZTdXARAFzcW1VaaruWW0Rr1+XHKKwDCz',
|
|
'i7HE76SO9qjnQfZCZG75CdQxI0h8GFeN3zsDqmhob2iSz2aJ1krtjM+iZ1FBFd57',
|
|
'OqCV6wmk5IT0RBN12ZzMS19YvzN/ONXHrmTZlKExd9Mh9RKLeVNw+bf6JsKQEzcY',
|
|
'JzFkBACX9X+hDYchO/2hiTwx4iOO9Fhsuh7eIWumB3gt+aUpm1jrSbas/QLTymmk',
|
|
'uZuQVXI4NtnlvzlNgWv4L5s5RU5WqNGG7WSaKNdcrvJZRC2dgbUJt04J5CKrWp6R',
|
|
'aIYal/81Ut1778lU01PEt563TcQnUBlnjU5OR25KhfSeN5CZY7QUVGVzdCA8dGVz',
|
|
'dEB0ZXN0LmNvbT6IYgQTEQIAIgUCURGXDgIbAwYLCQgHAwIGFQgCCQoLBBYCAwEC',
|
|
'HgECF4AACgkQikDlZK/UvLSspgCfcNaOpTg1W2ucR1JwBbBGvaERfuMAnRgt3/rs',
|
|
'EplqEakMckCtikEnpxYe',
|
|
'=b2Ln',
|
|
'-----END PGP PUBLIC KEY BLOCK-----'].join('\n');
|
|
|
|
const msg_arm1 =
|
|
['-----BEGIN PGP MESSAGE-----',
|
|
'Version: GnuPG v1.4.11 (GNU/Linux)',
|
|
'',
|
|
'hQEOA1N4OCSSjECBEAP/diDJCQn4e88193PgqhbfAkohk9RQ0v0MPnXpJbCRTHKO',
|
|
'8r9nxiAr/TQv4ZOingXdAp2JZEoE9pXxZ3r1UWew04czxmgJ8FP1ztZYWVFAWFVi',
|
|
'Tj930TBD7L1fY/MD4fK6xjEG7z5GT8k4tn4mLm/PpWMbarIglfMopTy1M/py2cID',
|
|
'/2Sj7Ikh3UFiG+zm4sViYc5roNbMy8ixeoKixxi99Mx8INa2cxNfqbabjblFyc0Z',
|
|
'BwmbIc+ZiY2meRNI5y/tk0gRD7hT84IXGGl6/mH00bsX/kkWdKGeTvz8s5G8RDHa',
|
|
'Za4HgLbXItkX/QarvRS9kvkD01ujHfj+1ZvgmOBttNfP0p8BQLIICqvg1eYD9aPB',
|
|
'+GtOZ2F3+k5VyBL5yIn/s65SBjNO8Fqs3aL0x+p7s1cfUzx8J8a8nWpqq/qIQIqg',
|
|
'ZJH6MZRKuQwscwH6NWgsSVwcnVCAXnYOpbHxFQ+j7RbF/+uiuqU+DFH/Rd5pik8b',
|
|
'0Dqnp0yfefrkjQ0nuvubgB6Rv89mHpnvuJfFJRInpg4lrHwLvRwdpN2HDozFHcKK',
|
|
'aOU=',
|
|
'=4iGt',
|
|
'-----END PGP MESSAGE-----'].join('\n');
|
|
|
|
const priv_key_arm2 =
|
|
['-----BEGIN PGP PRIVATE KEY BLOCK-----',
|
|
'Version: GnuPG v2.0.19 (GNU/Linux)',
|
|
'',
|
|
'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',
|
|
'=lw5e',
|
|
'-----END PGP PRIVATE KEY BLOCK-----'].join('\n');
|
|
|
|
const pub_key_arm2 =
|
|
['-----BEGIN PGP PUBLIC KEY BLOCK-----',
|
|
'Version: GnuPG v2.0.19 (GNU/Linux)',
|
|
'',
|
|
'mI0EUmEvTgEEANyWtQQMOybQ9JltDqmaX0WnNPJeLILIM36sw6zL0nfTQ5zXSS3+',
|
|
'fIF6P29lJFxpblWk02PSID5zX/DYU9/zjM2xPO8Oa4xo0cVTOTLj++Ri5mtr//f5',
|
|
'GLsIXxFrBJhD/ghFsL3Op0GXOeLJ9A5bsOn8th7x6JucNKuaRB6bQbSPABEBAAG0',
|
|
'JFRlc3QgTWNUZXN0aW5ndG9uIDx0ZXN0QGV4YW1wbGUuY29tPoi5BBMBAgAjBQJS',
|
|
'YS9OAhsvBwsJCAcDAgEGFQgCCQoLBBYCAwECHgECF4AACgkQSmNhOk1uQJQwDAP6',
|
|
'AgrTyqkRlJVqz2pb46TfbDM2TDF7o9CBnBzIGoxBhlRwpqALz7z2kxBDmwpQa+ki',
|
|
'Bq3jZN/UosY9y8bhwMAlnrDY9jP1gdCo+H0sD48CdXybblNwaYpwqC8VSpDdTndf',
|
|
'9j2wE/weihGp/DAdy/2kyBCaiOY1sjhUfJ1GogF49rC4jQRSYS9OAQQA6R/PtBFa',
|
|
'JaT4jq10yqASk4sqwVMsc6HcifM5lSdxzExFP74naUMMyEsKHP53QxTF0Grqusag',
|
|
'Qg/ZtgT0CN1HUM152y7ACOdp1giKjpMzOTQClqCoclyvWOFB+L/SwGEIJf7LSCEr',
|
|
'woBuJifJc8xAVr0XX0JthoW+uP91eTQ3XpsAEQEAAYkBPQQYAQIACQUCUmEvTgIb',
|
|
'LgCoCRBKY2E6TW5AlJ0gBBkBAgAGBQJSYS9OAAoJEOCE90RsICyXuqIEANmmiRCA',
|
|
'SF7YK7PvFkieJNwzeK0V3F2lGX+uu6Y3Q/Zxdtwc4xR+me/CSBmsURyXTO29OWhP',
|
|
'GLszPH9zSJU9BdDi6v0yNprmFPX/1Ng0Abn/sCkwetvjxC1YIvTLFwtUL/7v6NS2',
|
|
'bZpsUxRTg9+cSrMWWSNjiY9qUKajm1tuzPDZXAUEAMNmAN3xXN/Kjyvj2OK2ck0X',
|
|
'W748sl/tc3qiKPMJ+0AkMF7Pjhmh9nxqE9+QCEl7qinFqqBLjuzgUhBU4QlwX1GD',
|
|
'AtNTq6ihLMD5v1d82ZC7tNatdlDMGWnIdvEMCv2GZcuIqDQ9rXWs49e7tq1NncLY',
|
|
'hz3tYjKhoFTKEIq3y3Pp',
|
|
'=h/aX',
|
|
'-----END PGP PUBLIC KEY BLOCK-----'].join('\n');
|
|
|
|
const pub_key_arm3 =
|
|
['-----BEGIN PGP PUBLIC KEY BLOCK-----',
|
|
'Version: GnuPG v2.0.19 (GNU/Linux)',
|
|
'',
|
|
'mQENBFKV0FUBCACtZliApy01KBGbGNB36YGH4lpr+5KoqF1I8A5IT0YeNjyGisOk',
|
|
'WsDsUzOqaNvgzQ82I3MY/jQV5rLBhH/6LiRmCA16WkKcqBrHfNGIxJ+Q+ofVBHUb',
|
|
'aS9ClXYI88j747QgWzirnLuEA0GfilRZcewII1pDA/G7+m1HwV4qHsPataYLeboq',
|
|
'hPA3h1EVVQFMAcwlqjOuS8+weHQRfNVRGQdRMm6H7166PseDVRUHdkJpVaKFhptg',
|
|
'rDoNI0lO+UujdqeF1o5tVZ0j/s7RbyBvdLTXNuBbcpq93ceSWuJPZmi1XztQXKYe',
|
|
'y0f+ltgVtZDEc7TGV5WDX9erRECCcA3+s7J3ABEBAAG0G0pTIENyeXB0byA8ZGlm',
|
|
'ZmllQGhvbWUub3JnPokBPwQTAQIAKQUCUpXQVQIbAwUJCWYBgAcLCQgHAwIBBhUI',
|
|
'AgkKCwQWAgMBAh4BAheAAAoJENvyI+hwU030yRAIAKX/mGEgi/miqasbbQoyK/CS',
|
|
'a7sRxgZwOWQLdi2xxpE5V4W4HJIDNLJs5vGpRN4mmcNK2fmJAh74w0PskmVgJEhP',
|
|
'dFJ14UC3fFPq5nbqkBl7hU0tDP5jZxo9ruQZfDOWpHKxOCz5guYJ0CW97bz4fChZ',
|
|
'NFDyfU7VsJQwRIoViVcMCipP0fVZQkIhhwpzQpmVmN8E0a6jWezTZv1YpMdlzbEf',
|
|
'H79l3StaOh9/Un9CkIyqEWdYiKvIYms9nENyehN7r/OKYN3SW+qlt5GaL+ws+N1w',
|
|
'6kEZjPFwnsr+Y4A3oHcAwXq7nfOz71USojSmmo8pgdN8je16CP98vw3/k6TncLS5',
|
|
'AQ0EUpXQVQEIAMEjHMeqg7B04FliUFWr/8C6sJDb492MlGAWgghIbnuJfXAnUGdN',
|
|
'oAzn0S+n93Y/qHbW6YcjHD4/G+kK3MuxthAFqcVjdHZQXK0rkhXO/u1co7v1cdtk',
|
|
'OTEcyOpyLXolM/1S2UYImhrml7YulTHMnWVja7xu6QIRso+7HBFT/u9D47L/xXrX',
|
|
'MzXFVZfBtVY+yoeTrOY3OX9cBMOAu0kuN9eT18Yv2yi6XMzP3iONVHtl6HfFrAA7',
|
|
'kAtx4ne0jgAPWZ+a8hMy59on2ZFs/AvSpJtSc1kw/vMTWkyVP1Ky20vAPHQ6Ej5q',
|
|
'1NGJ/JbcFgolvEeI/3uDueLjj4SdSIbLOXMAEQEAAYkBJQQYAQIADwUCUpXQVQIb',
|
|
'DAUJCWYBgAAKCRDb8iPocFNN9NLkB/wO4iRxia0zf4Kw2RLVZG8qcuo3Bw9UTXYY',
|
|
'lI0AutoLNnSURMLLCq6rcJ0BCXGj/2iZ0NBxZq3t5vbRh6uUv+hpiSxK1nF7AheN',
|
|
'4aAAzhbWx0UDTF04ebG/neE4uDklRIJLhif6+Bwu+EUeTlGbDj7fqGSsNe8g92w7',
|
|
'1e41rF/9CMoOswrKgIjXAou3aexogWcHvKY2D+1q9exORe1rIa1+sUGl5PG2wsEs',
|
|
'znN6qtN5gMlGY1ofWDY+I02gO4qzaZ/FxRZfittCw7v5dmQYKot9qRi2Kx3Fvw+h',
|
|
'ivFBpC4TWgppFBnJJnAsFXZJQcejMW4nEmOViRQXY8N8PepQmgsu',
|
|
'=ummy',
|
|
'-----END PGP PUBLIC KEY BLOCK-----'].join('\n');
|
|
|
|
const pub_revoked =
|
|
['-----BEGIN PGP PUBLIC KEY BLOCK-----',
|
|
'Version: GnuPG v2.0.19 (GNU/Linux)',
|
|
'',
|
|
'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',
|
|
'pMiJM+NJAQ==',
|
|
'=ok+o',
|
|
'-----END PGP PUBLIC KEY BLOCK-----'].join('\n');
|
|
|
|
const pub_latin1_msg = `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
|
|
|
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
|
|
jC8YfR2rAYHeHGwwNIPsqYMjLXb0gMM7WKbakTG4FagSozqdDX4UtMWR9dH/AAAz
|
|
2f8AADPUARAAAQEAAAAAAAAAAAAAAAD/2P/gABBKRklGAAEBAQBIAEgAAP/hAIBF
|
|
eGlmAABNTQAqAAAACAAFARIAAwAAAAEAAQAAARoABQAAAAEAAABKARsABQAAAAEA
|
|
AABSASgAAwAAAAEAAgAAh2kABAAAAAEAAABaAAAAAAAAAEgAAAABAAAASAAAAAEA
|
|
AqACAAQAAAABAAAAfaADAAQAAAABAAAAlgAAAAD/4QkhaHR0cDovL25zLmFkb2Jl
|
|
LmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENl
|
|
aGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5z
|
|
Om1ldGEvIiB4OnhtcHRrPSJYTVAgQ29yZSA1LjQuMCI+IDxyZGY6UkRGIHhtbG5z
|
|
OnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5z
|
|
IyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiLz4gPC9yZGY6UkRGPiA8
|
|
L3g6eG1wbWV0YT4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
|
|
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
|
|
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
|
|
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
|
|
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
|
|
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
|
|
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
|
|
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
|
|
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
|
|
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
|
|
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
|
|
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
|
|
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
|
|
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
|
|
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
|
|
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
|
|
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
|
|
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
|
|
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
|
|
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
|
|
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
|
|
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
|
|
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
|
|
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
|
|
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
|
|
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
|
|
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
|
|
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
|
|
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
|
|
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
|
|
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
|
|
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
|
|
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
|
|
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
|
|
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
|
|
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
|
|
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
|
|
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
|
|
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
|
|
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
|
|
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
|
|
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
|
|
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8P3hw
|
|
YWNrZXQgZW5kPSJ3Ij8+AP/tADhQaG90b3Nob3AgMy4wADhCSU0EBAAAAAAAADhC
|
|
SU0EJQAAAAAAENQdjNmPALIE6YAJmOz4Qn7/4gzgSUNDX1BST0ZJTEUAAQEAAAzQ
|
|
YXBwbAIQAABtbnRyUkdCIFhZWiAH3wABAAEACwA7AC1hY3NwQVBQTAAAAAAAAAAA
|
|
AAAAAAAAAAAAAAAAAAAAAAAA9tYAAQAAAADTLWFwcGwAAAAAAAAAAAAAAAAAAAAA
|
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABFkZXNjAAABUAAAAGJkc2Nt
|
|
AAABtAAAAbhjcHJ0AAADbAAAACN3dHB0AAADkAAAABRyWFlaAAADpAAAABRnWFla
|
|
AAADuAAAABRiWFlaAAADzAAAABRyVFJDAAAD4AAACAxhYXJnAAAL7AAAACB2Y2d0
|
|
AAAMDAAAADBuZGluAAAMPAAAAD5jaGFkAAAMfAAAACxtbW9kAAAMqAAAAChiVFJD
|
|
AAAD4AAACAxnVFJDAAAD4AAACAxhYWJnAAAL7AAAACBhYWdnAAAL7AAAACBkZXNj
|
|
AAAAAAAAAAhEaXNwbGF5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
|
bWx1YwAAAAAAAAAiAAAADGhySFIAAAAQAAABqGtvS1IAAAAQAAABqG5iTk8AAAAQ
|
|
AAABqGlkAAAAAAAQAAABqGh1SFUAAAAQAAABqGNzQ1oAAAAQAAABqGRhREsAAAAQ
|
|
AAABqHVrVUEAAAAQAAABqGFyAAAAAAAQAAABqGl0SVQAAAAQAAABqHJvUk8AAAAQ
|
|
AAABqGVzRVMAAAAQAAABqGhlSUwAAAAQAAABqG5sTkwAAAAQAAABqGZpRkkAAAAQ
|
|
AAABqHpoVFcAAAAQAAABqHZpVk4AAAAQAAABqHNrU0sAAAAQAAABqHpoQ04AAAAQ
|
|
AAABqHJ1UlUAAAAQAAABqGZyRlIAAAAQAAABqG1zAAAAAAAQAAABqGNhRVMAAAAQ
|
|
AAABqHRoVEgAAAAQAAABqGVzWEwAAAAQAAABqGRlREUAAAAQAAABqGVuVVMAAAAQ
|
|
AAABqHB0QlIAAAAQAAABqHBsUEwAAAAQAAABqGVsR1IAAAAQAAABqHN2U0UAAAAQ
|
|
AAABqHRyVFIAAAAQAAABqGphSlAAAAAQAAABqHB0UFQAAAAQAAABqABTAE0AQgAx
|
|
ADkANAAwAFd0ZXh0AAAAAENvcHlyaWdodCBBcHBsZSBJbmMuLCAyMDE1AABYWVog
|
|
AAAAAAAA89gAAQAAAAEWCFhZWiAAAAAAAABwAAAAOREAAAPCWFlaIAAAAAAAAGI3
|
|
AAC3mgAAGRFYWVogAAAAAAAAJJ8AAA9VAAC2WmN1cnYAAAAAAAAEAAAAAAUACgAP
|
|
ABQAGQAeACMAKAAtADIANgA7AEAARQBKAE8AVABZAF4AYwBoAG0AcgB3AHwAgQCG
|
|
AIsAkACVAJoAnwCjAKgArQCyALcAvADBAMYAywDQANUA2wDgAOUA6wDwAPYA+wEB
|
|
AQcBDQETARkBHwElASsBMgE4AT4BRQFMAVIBWQFgAWcBbgF1AXwBgwGLAZIBmgGh
|
|
AakBsQG5AcEByQHRAdkB4QHpAfIB+gIDAgwCFAIdAiYCLwI4AkECSwJUAl0CZwJx
|
|
AnoChAKOApgCogKsArYCwQLLAtUC4ALrAvUDAAMLAxYDIQMtAzgDQwNPA1oDZgNy
|
|
A34DigOWA6IDrgO6A8cD0wPgA+wD+QQGBBMEIAQtBDsESARVBGMEcQR+BIwEmgSo
|
|
BLYExATTBOEE8AT+BQ0FHAUrBToFSQVYBWcFdwWGBZYFpgW1BcUF1QXlBfYGBgYW
|
|
BicGNwZIBlkGagZ7BowGnQavBsAG0QbjBvUHBwcZBysHPQdPB2EHdAeGB5kHrAe/
|
|
B9IH5Qf4CAsIHwgyCEYIWghuCIIIlgiqCL4I0gjnCPsJEAklCToJTwlkCXkJjwmk
|
|
CboJzwnlCfsKEQonCj0KVApqCoEKmAquCsUK3ArzCwsLIgs5C1ELaQuAC5gLsAvI
|
|
C+EL+QwSDCoMQwxcDHUMjgynDMAM2QzzDQ0NJg1ADVoNdA2ODakNww3eDfgOEw4u
|
|
DkkOZA5/DpsOtg7SDu4PCQ8lD0EPXg96D5YPsw/PD+wQCRAmEEMQYRB+EJsQuRDX
|
|
EPURExExEU8RbRGMEaoRyRHoEgcSJhJFEmQShBKjEsMS4xMDEyMTQxNjE4MTpBPF
|
|
E+UUBhQnFEkUahSLFK0UzhTwFRIVNBVWFXgVmxW9FeAWAxYmFkkWbBaPFrIW1hb6
|
|
Fx0XQRdlF4kXrhfSF/cYGxhAGGUYihivGNUY+hkgGUUZaxmRGbcZ3RoEGioaURp3
|
|
Gp4axRrsGxQbOxtjG4obshvaHAIcKhxSHHscoxzMHPUdHh1HHXAdmR3DHeweFh5A
|
|
HmoelB6+HukfEx8+H2kflB+/H+ogFSBBIGwgmCDEIPAhHCFIIXUhoSHOIfsiJyJV
|
|
IoIiryLdIwojOCNmI5QjwiPwJB8kTSR8JKsk2iUJJTglaCWXJccl9yYnJlcmhya3
|
|
JugnGCdJJ3onqyfcKA0oPyhxKKIo1CkGKTgpaymdKdAqAio1KmgqmyrPKwIrNitp
|
|
K50r0SwFLDksbiyiLNctDC1BLXYtqy3hLhYuTC6CLrcu7i8kL1ovkS/HL/4wNTBs
|
|
MKQw2zESMUoxgjG6MfIyKjJjMpsy1DMNM0YzfzO4M/E0KzRlNJ402DUTNU01hzXC
|
|
Nf02NzZyNq426TckN2A3nDfXOBQ4UDiMOMg5BTlCOX85vDn5OjY6dDqyOu87LTtr
|
|
O6o76DwnPGU8pDzjPSI9YT2hPeA+ID5gPqA+4D8hP2E/oj/iQCNAZECmQOdBKUFq
|
|
QaxB7kIwQnJCtUL3QzpDfUPARANER0SKRM5FEkVVRZpF3kYiRmdGq0bwRzVHe0fA
|
|
SAVIS0iRSNdJHUljSalJ8Eo3Sn1KxEsMS1NLmkviTCpMcky6TQJNSk2TTdxOJU5u
|
|
TrdPAE9JT5NP3VAnUHFQu1EGUVBRm1HmUjFSfFLHUxNTX1OqU/ZUQlSPVNtVKFV1
|
|
VcJWD1ZcVqlW91dEV5JX4FgvWH1Yy1kaWWlZuFoHWlZaplr1W0VblVvlXDVchlzW
|
|
XSddeF3JXhpebF69Xw9fYV+zYAVgV2CqYPxhT2GiYfViSWKcYvBjQ2OXY+tkQGSU
|
|
ZOllPWWSZedmPWaSZuhnPWeTZ+loP2iWaOxpQ2maafFqSGqfavdrT2una/9sV2yv
|
|
bQhtYG25bhJua27Ebx5veG/RcCtwhnDgcTpxlXHwcktypnMBc11zuHQUdHB0zHUo
|
|
dYV14XY+dpt2+HdWd7N4EXhueMx5KnmJeed6RnqlewR7Y3vCfCF8gXzhfUF9oX4B
|
|
fmJ+wn8jf4R/5YBHgKiBCoFrgc2CMIKSgvSDV4O6hB2EgITjhUeFq4YOhnKG14c7
|
|
h5+IBIhpiM6JM4mZif6KZIrKizCLlov8jGOMyo0xjZiN/45mjs6PNo+ekAaQbpDW
|
|
kT+RqJIRknqS45NNk7aUIJSKlPSVX5XJljSWn5cKl3WX4JhMmLiZJJmQmfyaaJrV
|
|
m0Kbr5wcnImc951kndKeQJ6unx2fi5/6oGmg2KFHobaiJqKWowajdqPmpFakx6U4
|
|
pammGqaLpv2nbqfgqFKoxKk3qamqHKqPqwKrdavprFys0K1ErbiuLa6hrxavi7AA
|
|
sHWw6rFgsdayS7LCszizrrQltJy1E7WKtgG2ebbwt2i34LhZuNG5SrnCuju6tbsu
|
|
u6e8IbybvRW9j74KvoS+/796v/XAcMDswWfB48JfwtvDWMPUxFHEzsVLxcjGRsbD
|
|
x0HHv8g9yLzJOsm5yjjKt8s2y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB
|
|
00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp22vvbgNwF3IrdEN2W3hzeot8p
|
|
36/gNuC94UThzOJT4tvjY+Pr5HPk/OWE5g3mlucf56noMui86Ubp0Opb6uXrcOv7
|
|
7IbtEe2c7ijutO9A78zwWPDl8XLx//KM8xnzp/Q09ML1UPXe9m32+/eK+Bn4qPk4
|
|
+cf6V/rn+3f8B/yY/Sn9uv5L/tz/bf//cGFyYQAAAAAAAwAAAAJmZgAA8qcAAA1Z
|
|
AAAT0AAACg52Y2d0AAAAAAAAAAEAAQAAAAAAAAABAAAAAQAAAAAAAAABAAAAAQAA
|
|
AAAAAAABAABuZGluAAAAAAAAADYAAKPAAABUQAAATMAAAJmAAAAmgAAAD0AAAFBA
|
|
AABUQAACMzMAAjMzAAIzMwAAAAAAAAAAc2YzMgAAAAAAAQu3AAAFlv//81cAAAcp
|
|
AAD91///+7f///2mAAAD2gAAwPZtbW9kAAAAAAAATC0AAAaVVjg5RchujAAAAAAA
|
|
AAAAAAAAAAAAAAAA/8AAEQgAlgB9AwEiAAIRAQMRAf/EAB8AAAEFAQEBAQEBAAAA
|
|
AAAAAAABAgMEBQYHCAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFB
|
|
BhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNE
|
|
RUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqi
|
|
o6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz
|
|
9PX29/j5+v/EAB8BAAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkKC//EALURAAIB
|
|
AgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1LwFWJy
|
|
0QoWJDThJfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpz
|
|
dHV2d3h5eoKDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXG
|
|
x8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz9PX29/j5+v/bAEMAAgICAgICAwICAwQD
|
|
AwMEBQQEBAQFBwUFBQUFBwgHBwcHBwcICAgICAgICAoKCgoKCgsLCwsLDQ0NDQ0N
|
|
DQ0NDf/bAEMBAgICAwMDBgMDBg0JBwkNDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0N
|
|
DQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDf/dAAQACP/aAAwDAQACEQMRAD8A/HD4
|
|
zajC3iQ6RHO91PYZFzMQETzWAO1FGcBRjJYkkmvMNE0271jV7PTLH/j5up0iiycA
|
|
Ox4JI6Y65r07Ufh5df8ACuJ/iXqs8n2i9nSWGHaMPHNLhpHY5PzZyoBHqa4Pwbf3
|
|
Ol+J9P1G0tTezW82+OBesj7WAH65/CvUx6lPE+0qqylqvS//AADzcDKCwzp0Hdwu
|
|
n25luP8AGWhXnhvxBe6NfSiee2kAeVc4kLgPuG4k98cntXNFMw+duX72zZn5umc4
|
|
9O2fWtrxBrGo69qdzq2qPvubiUs+BgDHAUAdAoGBWdfadfaZKkF/A8DyRrMqyDDb
|
|
JM7TjtnHQ8159VQ55ez+G+h20edU4qr8VtfXrYZaTR213BcSp5qRSI7J/eCkHH44
|
|
xX1n+x3d/avjqt1sC/aLLUX2L0UMY2AGOw6V8taRBZSXiNqZZbdQWbb1ZgPlXnoC
|
|
eprvPA3i6fwT4wk8SaCWRtk8carxtSYAHp9KylrFo6IRfNdI/o48FR/6JKPu7Zbg
|
|
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
|
|
Blk+CJ7ytHy6En8542bB/yC+Z9/zWbVuhg==
|
|
=jmT1
|
|
-----END PGP PUBLIC KEY BLOCK-----`;
|
|
|
|
const keyExpiredBindingSig = `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
|
|
|
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
|
|
hW1Hj9AO8lzggBQ=
|
|
=Nt+N
|
|
-----END PGP PUBLIC KEY BLOCK-----`;
|
|
|
|
const sequoiaBobPublicKey = `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
|
Comment: Bob's OpenPGP certificate
|
|
|
|
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
|
|
NEJd3XZRzaXZE2aAMQ==
|
|
=NXei
|
|
-----END PGP PUBLIC KEY BLOCK-----`;
|
|
|
|
const signature_with_critical_notation = `-----BEGIN PGP MESSAGE-----
|
|
|
|
owGbwMvMwMH4oOW7S46CznTG09xJDDE3Wl1KUotLuDousDAwcjBYiSmyXL+48d6x
|
|
U1PSGUxcj8IUszKBVMpMaWAAAgEGZpAeh9SKxNyCnFS95PzcytRiBi5OAZjyXXzM
|
|
f8WYLqv7TXP61Sa4rqT12CI3xaN73YS2pt089f96odCKaEPnWJ3iSGmzJaW/ug10
|
|
2Zo8Wj2k4s7t8wt4H3HtTu+y5UZfV3VOO+l//sdE/o+Lsub8FZH7/eOq7OnbNp4n
|
|
vwjE8mqJXetNMfj8r2SCyvkEnlVRYR+/mnge+ib56FdJ8uKtqSxyvgA=
|
|
=fRXs
|
|
-----END PGP MESSAGE-----`;
|
|
|
|
const signature_with_non_human_readable_notations = `-----BEGIN PGP SIGNATURE-----
|
|
|
|
wncEARYKAB8FAl2TS9MYFAAAAAAADAADdGVzdEBrZXkuY29tAQIDAAoJEGZ9
|
|
gtV/iL8hrhMBAOQ/UgqRTbx1Z8inGmRdUx1cJU1SR4Pnq/eJNH/CFk5DAP0Q
|
|
hUhMKMuiM3pRwdIyDOItkUWQmjEEw7/XmhgInkXsCw==
|
|
=ZGXr
|
|
-----END PGP SIGNATURE-----
|
|
`;
|
|
|
|
it('Retrieve the issuer Key ID of a signature', async function () {
|
|
const publicKey = await openpgp.readKey({ armoredKey: pub_key_arm2 });
|
|
const privateKey = await openpgp.decryptKey({
|
|
privateKey: await openpgp.readKey({ armoredKey: priv_key_arm2 }),
|
|
passphrase: 'hello world'
|
|
});
|
|
const message = await openpgp.createMessage({ text: 'test' });
|
|
const armoredSignature = await openpgp.sign({
|
|
message,
|
|
signingKeys: privateKey,
|
|
signingKeyIDs: privateKey.getKeyID(),
|
|
detached: true,
|
|
config: { minRSABits: 1024 }
|
|
});
|
|
const signature = await openpgp.readSignature({ armoredSignature });
|
|
expect(signature.getSigningKeyIDs).to.exist;
|
|
expect(signature.getSigningKeyIDs().map(x => x.toHex())).to.include(publicKey.getKeyID().toHex());
|
|
});
|
|
|
|
it('Generates valid one-pass signature packets (v6 keys)', async function () {
|
|
const v6PrivateKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
|
|
|
xUsGY4d/4xsAAAAg+U2nu0jWCmHlZ3BqZYfQMxmZu52JGggkLq2EVD34laMAGXKB
|
|
exK+cH6NX1hs5hNhIB00TrJmosgv3mg1ditlsLfCsQYfGwoAAABCBYJjh3/jAwsJ
|
|
BwUVCg4IDAIWAAKbAwIeCSIhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce6
|
|
2azJBScJAgcCAAAAAK0oIBA+LX0ifsDm185Ecds2v8lwgyU2kCcUmKfvBXbAf6rh
|
|
RYWzuQOwEn7E/aLwIwRaLsdry0+VcallHhSu4RN6HWaEQsiPlR4zxP/TP7mhfVEe
|
|
7XWPxtnMUMtf15OyA51YBMdLBmOHf+MZAAAAIIaTJINn+eUBXbki+PSAld2nhJh/
|
|
LVmFsS+60WyvXkQ1AE1gCk95TUR3XFeibg/u/tVY6a//1q0NWC1X+yui3O24wpsG
|
|
GBsKAAAALAWCY4d/4wKbDCIhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce6
|
|
2azJAAAAAAQBIKbpGG2dWTX8j+VjFM21J0hqWlEg+bdiojWnKfA5AQpWUWtnNwDE
|
|
M0g12vYxoWM8Y81W+bHBw805I8kWVkXU6vFOi+HWvv/ira7ofJu16NnoUkhclkUr
|
|
k0mXubZvyl4GBg==
|
|
-----END PGP PRIVATE KEY BLOCK-----` });
|
|
const v4PrivateKey = await openpgp.readKey({
|
|
armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
|
|
|
xVgEZOjwQBYJKwYBBAHaRw8BAQdAIzsYHb7T7NhSFmkWKSk5ItaBYv2HET7u
|
|
IFXhGdvOpogAAQDMk8SQlysNkLe7VRwXedX63St1a2V6/dzDG926oPyW3hJ6
|
|
zQ48dGVzdEB0ZXN0Lml0PsKMBBAWCgA+BYJk6PBABAsJBwgJkFMSwQwprjrH
|
|
AxUICgQWAAIBAhkBApsDAh4BFiEEwKKS1V/wldBNfwpjUxLBDCmuOscAAONc
|
|
AQDU1gi9moPtQzh6rrpKPWZ8nMSiZzLb3LYmpqz9Tn9YFAEAmEC2uHET/Oj6
|
|
VVxvMwvGytr5y0nuc6ZV5D0I2qoMcAHHXQRk6PBAEgorBgEEAZdVAQUBAQdA
|
|
xeBFSxzKOtLEQ6mVO2mnxvDiiMKmq7NbOezoWkbeSjgDAQgHAAD/YMvH+eDP
|
|
h1RplHOiaAMwhpTRGSGOaC6+pu6AMWiRLWAQ88J4BBgWCAAqBYJk6PBACZBT
|
|
EsEMKa46xwKbDBYhBMCiktVf8JXQTX8KY1MSwQwprjrHAAD4igEAzoExR6VX
|
|
EY9xxFKtAVdtYOT61d0FZibs0TD0VjbqzdkBAK60jT9jKefpnZ9sGv7bhSRX
|
|
2hrIPyCF2f0R5Js3LCML
|
|
=xyQ6
|
|
-----END PGP PRIVATE KEY BLOCK-----`
|
|
});
|
|
const armoredSignedMessage = await openpgp.sign({
|
|
message: await openpgp.createMessage({ text: 'test' }),
|
|
signingKeys: [v6PrivateKey, v4PrivateKey, v6PrivateKey] // get multiple signature packets
|
|
});
|
|
const signedMessage = await openpgp.readMessage({ armoredMessage: armoredSignedMessage });
|
|
// read signature packet stream
|
|
signedMessage.packets.push(...await stream.readToEnd(signedMessage.packets.stream, _ => _));
|
|
const signature1 = signedMessage.packets[4];
|
|
const signature2 = signedMessage.packets[5]; // v4 sig
|
|
const signature3 = signedMessage.packets[6];
|
|
const opsSignature1 = signedMessage.packets[2];
|
|
const opsSignature2 = signedMessage.packets[1];
|
|
const opsSignature3 = signedMessage.packets[0];
|
|
expect(opsSignature1).to.be.instanceOf(openpgp.OnePassSignaturePacket);
|
|
expect(signature1).to.be.instanceOf(openpgp.SignaturePacket);
|
|
expect(opsSignature2).to.be.instanceOf(openpgp.OnePassSignaturePacket);
|
|
expect(signature2).to.be.instanceOf(openpgp.SignaturePacket);
|
|
expect(opsSignature3).to.be.instanceOf(openpgp.OnePassSignaturePacket);
|
|
expect(signature3).to.be.instanceOf(openpgp.SignaturePacket);
|
|
expect(opsSignature1.version).to.equal(6);
|
|
expect(opsSignature2.version).to.equal(3);
|
|
expect(opsSignature3.version).to.equal(6);
|
|
expect(util.uint8ArrayToHex(opsSignature1.issuerFingerprint)).to.equal(v6PrivateKey.getFingerprint());
|
|
expect(util.uint8ArrayToHex(opsSignature3.issuerFingerprint)).to.equal(v6PrivateKey.getFingerprint());
|
|
expect(opsSignature1.salt).to.deep.equal(signature1.salt);
|
|
expect(opsSignature2.salt).to.be.null;
|
|
expect(opsSignature3.salt).to.deep.equal(signature3.salt);
|
|
expect(opsSignature1.salt).to.not.deep.equal(opsSignature3.salt); // sanity check
|
|
});
|
|
|
|
it('Throws when reading a signature missing the creation time', async function () {
|
|
const armoredSignature = `-----BEGIN PGP SIGNATURE-----
|
|
|
|
wsDtBAABCAAXFiEE0aZuGiOxgsmYD3iM+/zIKgFeczAACgkQ+/zIKgFeczDjiwv+
|
|
LFUWJohCYtauaVDHBDHWF+tojls+ducY6uuU6iUTBb1969okh2sjUmvPwIjrVXuk
|
|
cfPl616xRqVWolEU9T5sG6MjRlAaG31Oo/FVAVFXZn30ldEtuDss12+/IhES3Wfx
|
|
M1jGdJZ1ZMZJpRsNBJXBegEBFKbPleEd66seuuFfvoIUbgsdj7IT/ZlEMlixelWW
|
|
igXPVY1C05oPbkC8oo0lVSxwdq6gDvm8a52k3GCtXJELrYGH29C+eDqmyLP1zJOt
|
|
NBoZBAqMd9XYVrJtuip436D9pdo5pbg4zCE6uPf2zzx4taK7jGkk6nn7LqVDxvQm
|
|
3dAXUnIxw4V9eL3V8SFAKwmouUmHPRbjfnQ70hxYQxDXUcIwu1aYn13QS1s/F/jf
|
|
DVRZWaAhNdL9BfHfhEsRVsmjMhe0zwRpaepvXnERbnA/lAUHEmEvgfPFz/2GsAo/
|
|
kCNcH9WI6idSzFjuYegECf+ZA1xOCjS9oLTGbSeT7jNfC8dH5+E92qlBLq4Ctt7k
|
|
=lMU7
|
|
-----END PGP SIGNATURE-----`;
|
|
|
|
await expect(openpgp.readSignature({ armoredSignature })).to.be.rejectedWith(/Missing signature creation time/);
|
|
});
|
|
|
|
it('Supports parsing v6 signature with unknown hash algo', async function () {
|
|
// v6 signatures must check that the salt size is correct.
|
|
// but we want to support parsing signatures with unknown hash algos.
|
|
// this test checks that the parsing succeeds, while signing/verification fails.
|
|
|
|
// key with direct signature of unknown hash algo 99
|
|
const armoredKey = `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
|
|
|
xUsGZN8edBsAAAAgdUMlFMFCVKNo7sdUd6FVBos6NNjpUpSdrodk6BfPb/kA
|
|
+3buA2+WY2LwyxlX5o07WR2VSn+wuegC3v28yO0tClHCtwYfG2MAAABIBYJk
|
|
3x50BAsJCAcHFQ4MCgkICwIWAAIXgAKbAwIeCSIhBpbSe0QWuaCNSSLaePhX
|
|
EP3BxQ2VHX3WpW1U6svHvCUiBScJAgcCAAAAACMZIP8aHixoyC9wS3q/TNV/
|
|
IfOQa81f+U5Ucz6H4I+c5bWRYUzH/piBB4n5FoYlld+/SViCQIBCQ+fynLma
|
|
j5wlf22+mISTt/9je1ZfYWlJ+WSJyi5gY5EH9DubfuIU3VaqCM0aQmVybmFk
|
|
ZXR0ZSA8YkBleGFtcGxlLm9yZz7CugYTGw4AAABLBYJk3x50BAsJCAcHFQ4M
|
|
CgkICwIWAAIXgAIZAQKbAwIeCSIhBpbSe0QWuaCNSSLaePhXEP3BxQ2VHX3W
|
|
pW1U6svHvCUiBScJAgcCAAAAAMMGIJEi9+yqkFKsNwX1H5II0riPudFpwBx2
|
|
ypVjNk4aNb7Exl56Aac4tXEhz4fH41q0dAzFww2erZaiUqmohQ4AFSw1jN/W
|
|
OiDfb1DkjT/HJ8vXMGpwWdgFPoqsWzTNhd5VCQ==
|
|
-----END PGP PRIVATE KEY BLOCK-----`;
|
|
|
|
const key = await openpgp.readKey({ armoredKey });
|
|
await expect(key.getSigningKey()).to.be.rejectedWith(/Unsupported hash function/);
|
|
});
|
|
|
|
it('Ignores marker packets when verifying signatures', async function () {
|
|
const signatureWithMarkerPacket = `-----BEGIN PGP SIGNATURE-----
|
|
|
|
ygNQR1DCwPMEAAEKAAYFgl8831AAIQkQ+/zIKgFeczAWIQTRpm4aI7GCyZgPeIz7
|
|
/MgqAV5zMLckDACWiDbasKMTX/+czxHXyVcFJ/+ZeYqKEjYq6LueHy11XjJ0NZAM
|
|
LG9TqsXpWOsHrwE6wUQ7RvKQYtfIAeMUZtD87/XomIj6B/rQC5dHuQTb0b8lrRJb
|
|
OuW1sz6AYwceqkSvN3T5+KKNMXkaFw/DzWGPfqQQJDOqfgKxf5uO7GPVzaIU6aXn
|
|
76iKHQ7wowT2qHoFhd+t4S11iGr6XJef6QqIW2kTetZMf2Dp/rr7228VJJ1S0RdD
|
|
xxKJEbNrmdMNgE8/U+pkWjMQyVOOxWyPKlG3kv2Cu/naj4Lg2io3RhOAuNW5xEJF
|
|
gAId3WUNl3/PCu/PcTS1yS/Nj0ptwjKHwG0Zg8Dk5Jey8lUVyVhjxrV5tb6NLoAG
|
|
RlyTajZ3Sjhsg4mXHopjSF2w30saN64L5VAfGF1afFu7yzNYC+Fn6GL5yTJfKs4j
|
|
PNo4zCwOCumsVP0jWp09yUNflE6MTd21miBgbmPxyLyuwP2YrvT4+rCl+meNZ98a
|
|
cJRRGJPL16wINuk=
|
|
=VNoM
|
|
-----END PGP SIGNATURE-----`;
|
|
|
|
const key = await openpgp.readKey({ armoredKey: sequoiaBobPublicKey });
|
|
const message = await openpgp.createMessage({ text: 'Marker + Detached signature' });
|
|
const signature = await openpgp.readSignature({ armoredSignature: signatureWithMarkerPacket });
|
|
const { signatures: [sigInfo] } = await openpgp.verify({ message, signature, verificationKeys: key });
|
|
expect(await sigInfo.verified).to.be.true;
|
|
});
|
|
|
|
|
|
it('Testing signature checking on CAST5-enciphered message', async function() {
|
|
const publicKey = await openpgp.readKey({ armoredKey: pub_key_arm1 });
|
|
const privateKey = await openpgp.decryptKey({
|
|
privateKey: await openpgp.readKey({ armoredKey: priv_key_arm1 }),
|
|
passphrase: 'abcd'
|
|
});
|
|
const message = await openpgp.readMessage({ armoredMessage: msg_arm1 });
|
|
const config = {
|
|
rejectMessageHashAlgorithms: new Set([openpgp.enums.hash.md5, openpgp.enums.hash.ripemd]),
|
|
rejectPublicKeyAlgorithms: new Set()
|
|
};
|
|
const { data, signatures } = await openpgp.decrypt({ decryptionKeys: privateKey, verificationKeys: publicKey, message, config });
|
|
expect(data).to.exist;
|
|
expect(await signatures[0].verified).to.be.true;
|
|
expect((await signatures[0].signature).packets.length).to.equal(1);
|
|
});
|
|
|
|
it('Consider signature expired at the expiration time', async function() {
|
|
const key = await openpgp.readKey({ armoredKey: keyExpiredBindingSig });
|
|
const { embeddedSignature } = key.subkeys[0].bindingSignatures[0];
|
|
expect(embeddedSignature.isExpired(embeddedSignature.created)).to.be.false;
|
|
expect(embeddedSignature.isExpired(new Date(embeddedSignature.getExpirationTime() - 1))).to.be.false;
|
|
expect(embeddedSignature.isExpired(embeddedSignature.getExpirationTime())).to.be.true;
|
|
});
|
|
|
|
it('Signing fails if primary key is expired', async function() {
|
|
const armoredExpiredKey = `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
|
|
|
xVgEYKKPDRYJKwYBBAHaRw8BAQdAwJcSQMkHVnZPesPJP1JaB9ptV+wG8Io1
|
|
vxRKvXQe0wMAAP0fdn6gvpVwFUE4bIRcn9hx6eDxSxUu+tg/t959Oo+iahF1
|
|
zRB0ZXN0IDx0ZXN0QGEuaXQ+wpIEEBYKACMFAmCijw0FCQAAAAEECwkHCAMV
|
|
CAoEFgACAQIZAQIbAwIeAQAhCRD16pevybCusRYhBHjm9svlAjmgVWL4wvXq
|
|
l6/JsK6xGUQBAPzxKS2Qs+vWGpxPT2N2T+PLHIgCOxVJVngj4fzREFH1AP9t
|
|
wP+fn3eSsik+vFGy93REmlD1xdu7nW/sHuxY4roqBcddBGCijw0SCisGAQQB
|
|
l1UBBQEBB0Cl1lr+aHfy6V4ePmZUULK6VKTCTPTMaPpR2TzKNIJQBQMBCAcA
|
|
AP9DZWRqQLCIkF38Q0UC/YXLCDdBEQdnlwpHgA0W1bSWmA3uwn4EGBYIAA8F
|
|
AmCijw0FCQAAAAECGwwAIQkQ9eqXr8mwrrEWIQR45vbL5QI5oFVi+ML16pev
|
|
ybCusYE4AQCYbXw8ZWoMevbOM7lAttkwyrG3V/nTW6BVo7/M9Pr9swEA0mDI
|
|
DQmhI0SZoTKy4EGhS0bNJ+g2+dJ8Y22fKzLWXwo=
|
|
=qiIN
|
|
-----END PGP PRIVATE KEY BLOCK-----`;
|
|
const key = await openpgp.readKey({ armoredKey: armoredExpiredKey });
|
|
await expect(openpgp.sign({
|
|
signingKeys: key,
|
|
message: await openpgp.createMessage({ text: 'Hello World' })
|
|
})).to.be.rejectedWith(/key is expired/);
|
|
});
|
|
|
|
it('Signing fails if the signing date is before the key creation date', async function() {
|
|
const key = await openpgp.decryptKey({
|
|
privateKey: await openpgp.readKey({ armoredKey: priv_key_arm2 }),
|
|
passphrase: 'hello world'
|
|
});
|
|
await expect(openpgp.sign({
|
|
signingKeys: key,
|
|
date: new Date(key.keyPacket.created - 3600),
|
|
message: await openpgp.createMessage({ text: 'Hello World' }),
|
|
config: { minRSABits: 1024 }
|
|
})).to.be.rejectedWith(/Signature creation time is in the future/);
|
|
});
|
|
|
|
it('Verification fails if primary key binding signature is expired', async function() {
|
|
const armoredSignature = `-----BEGIN PGP SIGNATURE-----
|
|
|
|
wsDzBAABCgAGBYJfLAFsACEJEHwvqk35PDeyFiEEHdzhXwkhfO4vOzdgfC+qTfk8
|
|
N7KiqwwAts4QGB7v9bABCC2qkTxJhmStC0wQMcHRcjL/qAiVnmasQWmvE9KVsdm3
|
|
AaXd8mIx4a37/RRvr9dYrY2eE4uw72cMqPxNja2tvVXkHQvk1oEUqfkvbXs4ypKI
|
|
NyeTWjXNOTZEbg0hbm3nMy+Wv7zgB1CEvAsEboLDJlhGqPcD+X8a6CJGrBGUBUrv
|
|
KVmZr3U6vEzClz3DBLpoddCQseJRhT4YM1nKmBlZ5quh2LFgTSpajv5OsZheqt9y
|
|
EZAPbqmLhDmWRQwGzkWHKceKS7nZ/ox2WK6OS7Ob8ZGZkM64iPo6/EGj5Yc19vQN
|
|
AGiIaPEGszBBWlOpHTPhNm0LB0nMWqqaT87oNYwP8CQuuxDb6rKJ2lffCmZH27Lb
|
|
UbQZcH8J+0UhpeaiadPZxH5ATJAcenmVtVVMLVOFnm+eIlxzov9ntpgGYt8hLdXB
|
|
ITEG9mMgp3TGS9ZzSifMZ8UGtHdp9QdBg8NEVPFzDOMGxpc/Bftav7RRRuPiAER+
|
|
7A5CBid5
|
|
=aQkm
|
|
-----END PGP SIGNATURE-----`;
|
|
const key = await openpgp.readKey({ armoredKey: keyExpiredBindingSig });
|
|
const signature = await openpgp.readSignature({ armoredSignature });
|
|
const { signatures: [sigInfo] } = await openpgp.verify({
|
|
verificationKeys: key,
|
|
message: await openpgp.createMessage({ text: 'Hello World :)' }),
|
|
signature
|
|
});
|
|
await expect(sigInfo.verified).to.be.rejectedWith(/Signature is expired/);
|
|
});
|
|
|
|
it('Verification fails if signing key\'s self-sig were created after the time of signing, unless config allows it', async function() {
|
|
const armoredReformattedKey = `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
|
|
|
xVgEYWmlshYJKwYBBAHaRw8BAQdAAxpFNPiHxz9q4HBzWqveHdP/knjwlgv8
|
|
pEQCMHDpIZIAAP9WFlwHDuVlvNb7CyoikwmG01nmdMDe9wXQRWA5vasWKA+g
|
|
zSV0ZXN0QHJlZm9ybWF0LmNvbSA8dGVzdEByZWZvcm1hdC5jb20+wowEEBYK
|
|
AB0FAmFppjQECwkHCAMVCAoEFgACAQIZAQIbAwIeAQAhCRAOZNKOg+/XQxYh
|
|
BGqP/hIaYCSJsZ4TrQ5k0o6D79dD+c8BAIXdh2hrC+l49WPN/KZF+ZzvWCWa
|
|
W5n+ozbp/sOGXvODAP4oGEj0RUDDA33b6x7fhQysBZxdrrnHxP9AXEdOTQC3
|
|
CsddBGFppbISCisGAQQBl1UBBQEBB0Cjy8Z2K7rl6J6AK1lCfVozmyLE0Gbv
|
|
1cspce6oCF6oCwMBCAcAAP9OL5V80EaYm2ic19aM+NtTj4UNOqKqIt10AaH9
|
|
SlcdMBDgwngEGBYIAAkFAmFppjQCGwwAIQkQDmTSjoPv10MWIQRqj/4SGmAk
|
|
ibGeE60OZNKOg+/XQx/EAQCM0UYrObp60YbOCxu07Dm6XjCVylbOcsaxCnE7
|
|
2eMU4AD+OkgajZgbqSIdAR1ud76FW+W+3xlDi/SMFdU7D49SbQI=
|
|
=ASQu
|
|
-----END PGP PRIVATE KEY BLOCK-----`;
|
|
const armoredMessage = `-----BEGIN PGP MESSAGE-----
|
|
|
|
xA0DAQoWDmTSjoPv10MByw91AGFpplFwbGFpbnRleHTCdQQBFgoABgUCYWml
|
|
sgAhCRAOZNKOg+/XQxYhBGqP/hIaYCSJsZ4TrQ5k0o6D79dDDWwBAKUnRWXj
|
|
P3HTW521iD/DngK54mYS3feQzhDokhkYjO3UAP0ZlsYShKaJvXh+JgvR5BPP
|
|
gjVcn04JVVlxqgVnMqeVBw==
|
|
=eyO7
|
|
-----END PGP MESSAGE-----`;
|
|
// the key was reformatted and the message signature date preceeds the key self-signature creation date
|
|
const key = await openpgp.readKey({ armoredKey: armoredReformattedKey });
|
|
const { signatures: [sigInfoRejected] } = await openpgp.verify({
|
|
verificationKeys: key,
|
|
message: await openpgp.readMessage({ armoredMessage })
|
|
});
|
|
await expect(sigInfoRejected.verified).to.be.rejectedWith(/Signature creation time is in the future/);
|
|
|
|
// since the key is valid at the current time, the message should be verifiable if the `config` allows it
|
|
const { signatures: [sigInfoValid] } = await openpgp.verify({
|
|
verificationKeys: key,
|
|
message: await openpgp.readMessage({ armoredMessage }),
|
|
config: { allowInsecureVerificationWithReformattedKeys: true }
|
|
});
|
|
expect(await sigInfoValid.verified).to.be.true;
|
|
});
|
|
|
|
it('Verification fails if signing key was already expired at the time of signing (one-pass signature, streamed)', async function() {
|
|
const armoredMessage = `-----BEGIN PGP MESSAGE-----
|
|
|
|
xA0DAQgB4IT3RGwgLJcByxR1AGCc8BxIZWxsbyBXb3JsZCA6KcKzBAEBCAAG
|
|
BQJgnPAcACEJEOCE90RsICyXFiEE19Gx3sbKlGcANEXF4IT3RGwgLJdssAP+
|
|
KpyVi30z5iMckULAQ3Q34IB29Gxa1/99ABSld6iIVGRCfmZZlS5UGcxJJGoL
|
|
vZ1RAL4YQx/GLV1dBcKWFwzb5G2/ip4coDMCDGTAwnwjcPwjHpfMQ9gX59mG
|
|
AkLaG/AkATpuH+DMkYDmKbDLGgD+N4yuxXBJmBfC2IBe4J1S2Gg=
|
|
=zvNP
|
|
-----END PGP MESSAGE-----`;
|
|
const key = await openpgp.decryptKey({
|
|
privateKey: await openpgp.readKey({ armoredKey: priv_key_arm2 }),
|
|
passphrase: 'hello world'
|
|
});
|
|
const { privateKey: expiredKey } = await openpgp.reformatKey({
|
|
privateKey: key,
|
|
userIDs: key.users.map(user => user.userID),
|
|
keyExpirationTime: 1,
|
|
date: key.keyPacket.created,
|
|
format: 'object'
|
|
});
|
|
await loadStreamsPolyfill();
|
|
const { signatures: [sigInfo] } = await openpgp.verify({
|
|
verificationKeys: expiredKey,
|
|
message: await openpgp.readMessage({ armoredMessage: stream.toStream(armoredMessage) }),
|
|
config: { minRSABits: 1024 }
|
|
|
|
});
|
|
await expect(sigInfo.verified).to.be.rejectedWith(/Primary key is expired/);
|
|
});
|
|
|
|
it('Verification fails if signing key was already expired at the time of signing (standard signature)', async function() {
|
|
const armoredMessage = `-----BEGIN PGP MESSAGE-----
|
|
|
|
wrMEAQEIAAYFAmCc8BwAIQkQ4IT3RGwgLJcWIQTX0bHexsqUZwA0RcXghPdE
|
|
bCAsl2ywA/4qnJWLfTPmIxyRQsBDdDfggHb0bFrX/30AFKV3qIhUZEJ+ZlmV
|
|
LlQZzEkkagu9nVEAvhhDH8YtXV0FwpYXDNvkbb+KnhygMwIMZMDCfCNw/CMe
|
|
l8xD2Bfn2YYCQtob8CQBOm4f4MyRgOYpsMsaAP43jK7FcEmYF8LYgF7gnVLY
|
|
aMsUdQBgnPAcSGVsbG8gV29ybGQgOik=
|
|
=s9xh
|
|
-----END PGP MESSAGE-----`;
|
|
const key = await openpgp.decryptKey({
|
|
privateKey: await openpgp.readKey({ armoredKey: priv_key_arm2 }),
|
|
passphrase: 'hello world'
|
|
});
|
|
const { privateKey: expiredKey } = await openpgp.reformatKey({
|
|
privateKey: key,
|
|
userIDs: key.users.map(user => user.userID),
|
|
keyExpirationTime: 1,
|
|
date: key.keyPacket.created,
|
|
format: 'object'
|
|
});
|
|
await loadStreamsPolyfill();
|
|
const { signatures: [sigInfo] } = await openpgp.verify({
|
|
verificationKeys: expiredKey,
|
|
message: await openpgp.readMessage({ armoredMessage: stream.toStream(armoredMessage) }),
|
|
config: { minRSABits: 1024 }
|
|
});
|
|
await expect(sigInfo.verified).to.be.rejectedWith(/Primary key is expired/);
|
|
});
|
|
|
|
it('Verification succeeds if an expired signing key was valid at the time of signing (with streaming)', async function() {
|
|
const armoredMessage = `-----BEGIN PGP MESSAGE-----
|
|
|
|
xA0DAQgB4IT3RGwgLJcByxF1AGCdJvJoZWxsbyB3b3JsZMKzBAEBCAAGBQJS
|
|
YS9OACEJEOCE90RsICyXFiEE19Gx3sbKlGcANEXF4IT3RGwgLJcPBQP/csZd
|
|
9AhZQ3+dPkwlqlsXqYMlVEagYDavlUDI2CEJ2cn1rqHBuMlRkmYs7UqODku4
|
|
FhJ6WvghiEKx8vqghDuaUXmcKuXhYe+PomD4XBmpbURBXCdPnojTINUj7GPK
|
|
eSvSZutLuKKbidSYMLhWROPlwKc2GU2ws6PrLZAyCAel/lU=
|
|
=xDib
|
|
-----END PGP MESSAGE-----`;
|
|
const key = await openpgp.decryptKey({
|
|
privateKey: await openpgp.readKey({ armoredKey: priv_key_arm2 }),
|
|
passphrase: 'hello world'
|
|
});
|
|
const { privateKey: expiredKey } = await openpgp.reformatKey({
|
|
privateKey: key,
|
|
userIDs: key.users.map(user => user.userID),
|
|
keyExpirationTime: 1,
|
|
date: key.keyPacket.created,
|
|
format: 'object'
|
|
});
|
|
await loadStreamsPolyfill();
|
|
const { signatures: [sigInfo] } = await openpgp.verify({
|
|
verificationKeys: expiredKey,
|
|
message: await openpgp.readMessage({ armoredMessage: stream.toStream(armoredMessage) }),
|
|
config: { minRSABits: 1024 }
|
|
});
|
|
expect(await sigInfo.verified).to.be.true;
|
|
});
|
|
|
|
it('Verification succeeds if an expired signing key was valid at the time of signing (without streaming)', async function() {
|
|
const armoredMessage = `-----BEGIN PGP MESSAGE-----
|
|
|
|
xA0DAQgB4IT3RGwgLJcByxF1AGCdJvJoZWxsbyB3b3JsZMKzBAEBCAAGBQJS
|
|
YS9OACEJEOCE90RsICyXFiEE19Gx3sbKlGcANEXF4IT3RGwgLJcPBQP/csZd
|
|
9AhZQ3+dPkwlqlsXqYMlVEagYDavlUDI2CEJ2cn1rqHBuMlRkmYs7UqODku4
|
|
FhJ6WvghiEKx8vqghDuaUXmcKuXhYe+PomD4XBmpbURBXCdPnojTINUj7GPK
|
|
eSvSZutLuKKbidSYMLhWROPlwKc2GU2ws6PrLZAyCAel/lU=
|
|
=xDib
|
|
-----END PGP MESSAGE-----`;
|
|
const key = await openpgp.decryptKey({
|
|
privateKey: await openpgp.readKey({ armoredKey: priv_key_arm2 }),
|
|
passphrase: 'hello world'
|
|
});
|
|
const { privateKey: expiredKey } = await openpgp.reformatKey({
|
|
privateKey: key,
|
|
userIDs: key.users.map(user => user.userID),
|
|
keyExpirationTime: 1,
|
|
date: key.keyPacket.created,
|
|
format: 'object'
|
|
});
|
|
const { signatures: [sigInfo] } = await openpgp.verify({
|
|
verificationKeys: expiredKey,
|
|
message: await openpgp.readMessage({ armoredMessage }),
|
|
config: { minRSABits: 1024 }
|
|
});
|
|
expect(await sigInfo.verified).to.be.true;
|
|
});
|
|
|
|
it('Verification fails if v6 signature has unexpected salt length', async function() {
|
|
// signature with salt shorter than expected
|
|
const armoredMessage = `-----BEGIN PGP MESSAGE-----
|
|
|
|
xDQGAQgbDpdDiCIrq6YZAf5vD3wFIucHRyMNlExatdj6sQcW2FA/vV5eZGCv
|
|
mBUS4Mqqki4ByxR1AGUddyNUaGlzIGlzIHNpZ25lZMKGBgEbCAAAACkFgmUd
|
|
dyMioQYi5wdHIw2UTFq12PqxBxbYUD+9Xl5kYK+YFRLgyqqSLgAAAADZ9w6X
|
|
Q4giK6umGQH+bw98BS96KSXxW39Ue6hNxbSoc5xOqYnTsD+75FYdR1U9fco/
|
|
HDpH7axPa2euIDpwT60NedSjcTx7C9Sots4mTvjMwQQ=
|
|
-----END PGP MESSAGE-----`;
|
|
const key = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
|
|
|
xUsGZR13GRsAAAAgcCI5M7vPn+9uD1ii8nnT/schP5BjXXTyr+q7EmSlcaoA
|
|
/OkLygFTbUdwt6hMlfcNyUmS058WSIHxaVtG4uSfyjbCmQYfGwgAAAA6BYJl
|
|
HXcZAwsJBwMVCAoCFgACmwMCHgEioQYi5wdHIw2UTFq12PqxBxbYUD+9Xl5k
|
|
YK+YFRLgyqqSLgAAAABCZxAAxl8ycoAAY74DEPZDnfSYLP+dqdM8QZ3b/Mp4
|
|
fnzOcVI4RvaxAjp3GZVXxisSS36A2fUx2lpj38y1tIvnnlShfpuylTp73foT
|
|
DVf/bROnAM0AwosGEBsIAAAALAWCZR13GQIZASKhBiLnB0cjDZRMWrXY+rEH
|
|
FthQP71eXmRgr5gVEuDKqpIuAAAAAFEEEFrhrlN40SgxwpL3UaSWs6F5pD83
|
|
AOtaXLA/e9gFPNgiLnuid3AqUaFa6JlhWf4N/Md6SMQJ5cC7ATxTJ2a3xAMY
|
|
5UsE6+HN099QVLx95CMP
|
|
-----END PGP PRIVATE KEY BLOCK-----` });
|
|
|
|
const { signatures } = await openpgp.verify({
|
|
message: await openpgp.readMessage({ armoredMessage }),
|
|
verificationKeys: key
|
|
});
|
|
expect(signatures).to.have.length(1);
|
|
await expect(signatures[0].verified).to.be.rejectedWith(/Signature salt does not have the expected length/);
|
|
});
|
|
|
|
it('Reject cleartext message with arbitrary text added around hash headers (spoofed cleartext message)', async function() {
|
|
await expect(openpgp.readCleartextMessage({ cleartextMessage: `-----BEGIN PGP SIGNED MESSAGE-----
|
|
This is not signed but you might think it is Hash: SHA512
|
|
|
|
This is signed
|
|
-----BEGIN PGP SIGNATURE-----
|
|
|
|
wnUEARYKACcFgmTsqxgJkEhlqJkkhIfRFiEEUA/OS4xZ3EwNC5l8SGWomSSE
|
|
h9EAALyPAQDDR0IYwq/5XMVSYPWojBamM4NhcP5arA656ALIq9cJYAEAlw0H
|
|
Fk7EflUZzngwY4lBzYAfnNBjEjc30xD/ddo+rwE=
|
|
=O7mt
|
|
-----END PGP SIGNATURE-----` })).to.be.rejectedWith(/Only "Hash" header allowed/);
|
|
|
|
await expect(openpgp.readCleartextMessage({ cleartextMessage: `-----BEGIN PGP SIGNED MESSAGE-----
|
|
Hash: SHA512\vThis is not signed but you might think it is
|
|
|
|
This is signed
|
|
-----BEGIN PGP SIGNATURE-----
|
|
|
|
wnUEARYKACcFgmTsqxgJkEhlqJkkhIfRFiEEUA/OS4xZ3EwNC5l8SGWomSSE
|
|
h9EAALyPAQDDR0IYwq/5XMVSYPWojBamM4NhcP5arA656ALIq9cJYAEAlw0H
|
|
Fk7EflUZzngwY4lBzYAfnNBjEjc30xD/ddo+rwE=
|
|
=O7mt
|
|
-----END PGP SIGNATURE-----` })).to.be.rejectedWith(/Unknown hash algorithm in armor header/);
|
|
});
|
|
|
|
it('Supports non-human-readable notations', async function() {
|
|
const { packets: [signature] } = await openpgp.readSignature({ armoredSignature: signature_with_non_human_readable_notations });
|
|
// There are no human-readable notations so `notations` property does not
|
|
// expose the `test@key.com` notation.
|
|
expect(Object.keys(signature.notations).length).to.equal(0);
|
|
expect(signature.notations['test@key.com']).to.equal(undefined);
|
|
|
|
// The notation is readable through `rawNotations` property:
|
|
expect(signature.rawNotations.length).to.equal(1);
|
|
const notation = signature.rawNotations[0];
|
|
expect(notation.name).to.equal('test@key.com');
|
|
expect(notation.value).to.deep.equal(new Uint8Array([0x01, 0x02, 0x03]));
|
|
expect(notation.humanReadable).to.equal(false);
|
|
});
|
|
|
|
it('Verify V4 signature. Hash: SHA1. PK: RSA. Signature Type: 0x00 (binary document)', async function() {
|
|
const { rejectMessageHashAlgorithms, minRSABits } = openpgp.config;
|
|
Object.assign(openpgp.config, {
|
|
rejectMessageHashAlgorithms: new Set([openpgp.enums.hash.md5, openpgp.enums.hash.ripemd]),
|
|
minRSABits: 1024
|
|
});
|
|
try {
|
|
const signedArmor =
|
|
['-----BEGIN PGP MESSAGE-----',
|
|
'Version: GnuPG v2.0.19 (GNU/Linux)',
|
|
'',
|
|
'owGbwMvMwMT4oOW7S46CznTGNeZJLCWpFSVBU3ZGF2fkF5Uo5KYWFyemp3LlAUUV',
|
|
'cjLzUrneTp3zauvaN9O26L9ZuOFNy4LXyydwcXXMYWFgZGJgY2UCaWXg4hSAmblK',
|
|
'nPmfsXYxd58Ka9eVrEnSpzilr520fXBrJsf2P/oTqzTj3hzyLG0o3TTzxFfrtOXf',
|
|
'cw6U57n3/Z4X0pEZ68C5/o/6NpPICD7fuEOz3936raZ6wXGzueY8pfPnVjY0ajAc',
|
|
'PtJzvvqj+ubYaT1sK9wWhd9lL3/V+9Zuua9QjOWC22buchsCroh8fLoZAA==',
|
|
'=VH8F',
|
|
'-----END PGP MESSAGE-----'].join('\n');
|
|
|
|
const sMsg = await openpgp.readMessage({ armoredMessage: signedArmor });
|
|
const pub_key = await openpgp.readKey({ armoredKey: pub_key_arm2 });
|
|
const verified = await sMsg.verify([pub_key]);
|
|
stream.readToEnd(sMsg.getLiteralData());
|
|
expect(verified).to.exist;
|
|
expect(verified).to.have.length(1);
|
|
expect(await verified[0].verified).to.be.true;
|
|
expect((await verified[0].signature).packets.length).to.equal(1);
|
|
} finally {
|
|
Object.assign(openpgp.config, { rejectMessageHashAlgorithms, minRSABits });
|
|
}
|
|
});
|
|
|
|
it('Verify signature of signed and encrypted message from GPG2 with openpgp.decrypt', async function() {
|
|
const msg_armor =
|
|
['-----BEGIN PGP MESSAGE-----',
|
|
'Version: GnuPG v2.0.19 (GNU/Linux)',
|
|
'',
|
|
'hIwD4IT3RGwgLJcBBADEBdm+GEW7IV1K/Bykg0nB0WYO08ai7/8/+Y/O9xu6RiU0',
|
|
'q7/jWuKms7kSjw9gxMCjf2dGnAuT4Cg505Kj5WfeBuHh618ovO8qo4h0qHyp1/y3',
|
|
'o1P0IXPAb+LGJOeO7DyM9Xp2AOBiIKOVWzFTg+MBZOc+XZEVx3FioHfm9SSDudLA',
|
|
'WAEkDakCG6MRFj/7SmOiV8mQKH+YPMKT69eDZW7hjINabrpM2pdRU7c9lC7CMUBx',
|
|
'Vj7wZsQBMASSC8f2rhpGA2iKvYMsmW3g9R1xkvj1MXWftSPUS4jeNTAgEwvvF6Af',
|
|
'cP+OYSXKlTbwfEr73ES2O3/IFE9sHRjPqWaxWuv4DDQ5YfIxE54C1aE8Aq5/QaIH',
|
|
'v38TUSia0yEMCc/tJd58DikkT07AF162tcx9Ro0ZjhudyuvUyXIfPfxA+XWR2pdz',
|
|
'ifxyV4zia9RvaCUY8vXGM+gQJ3NNXx2LkZA3kWUEyxFVL1Vl/XUQY0M6U+uccSk4',
|
|
'eMXm6eyEWDcj0lBRckqKoKo1w/uan11jPuHsnRz6jO9DsuKEz79UDgI=',
|
|
'=cFi7',
|
|
'-----END PGP MESSAGE-----'].join('\n');
|
|
|
|
const plaintext = 'short message\nnext line\n한국어/조선말';
|
|
const message = await openpgp.readMessage({ armoredMessage: msg_armor });
|
|
const pubKey = await openpgp.readKey({ armoredKey: pub_key_arm2 });
|
|
const privKey = await openpgp.decryptKey({
|
|
privateKey: await openpgp.readKey({ armoredKey: priv_key_arm2 }),
|
|
passphrase: 'hello world'
|
|
});
|
|
|
|
return openpgp.decrypt({
|
|
decryptionKeys: privKey, verificationKeys: pubKey , message, config: { minRSABits: 1024 }
|
|
}).then(async ({ signatures, data }) => {
|
|
expect(data).to.exist;
|
|
expect(data).to.equal(plaintext);
|
|
expect(signatures).to.have.length(1);
|
|
expect(await signatures[0].verified).to.be.true;
|
|
expect((await signatures[0].signature).packets.length).to.equal(1);
|
|
});
|
|
});
|
|
|
|
|
|
it('Verify signed message with a v6 one pass signature', async function() {
|
|
// test vector from https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#appendix-A.7
|
|
const message = await openpgp.readMessage({ armoredMessage: `-----BEGIN PGP MESSAGE-----
|
|
|
|
xEYGAQobIHZJX1AhiJD39eLuPBgiUU9wUA9VHYblySHkBONKU/usyxhsTwYJppfk
|
|
1S36bHIrDB8eJ8GKVnCPZSXsJ7rZrMkBy0p1AAAAAABXaGF0IHdlIG5lZWQgZnJv
|
|
bSB0aGUgZ3JvY2VyeSBzdG9yZToKCi0gdG9mdQotIHZlZ2V0YWJsZXMKLSBub29k
|
|
bGVzCsKYBgEbCgAAACkFgmOYo2MiIQbLGGxPBgmml+TVLfpscisMHx4nwYpWcI9l
|
|
JewnutmsyQAAAABpNiB2SV9QIYiQ9/Xi7jwYIlFPcFAPVR2G5ckh5ATjSlP7rCfQ
|
|
b7gKqPxbyxbhljGygHQPnqau1eBzrQD5QVplPEDnemrnfmkrpx0GmhCfokxYz9jj
|
|
FtCgazStmsuOXF9SFQE=
|
|
-----END PGP MESSAGE-----` });
|
|
const key = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
|
|
|
xioGY4d/4xsAAAAg+U2nu0jWCmHlZ3BqZYfQMxmZu52JGggkLq2EVD34laPCsQYf
|
|
GwoAAABCBYJjh3/jAwsJBwUVCg4IDAIWAAKbAwIeCSIhBssYbE8GCaaX5NUt+mxy
|
|
KwwfHifBilZwj2Ul7Ce62azJBScJAgcCAAAAAK0oIBA+LX0ifsDm185Ecds2v8lw
|
|
gyU2kCcUmKfvBXbAf6rhRYWzuQOwEn7E/aLwIwRaLsdry0+VcallHhSu4RN6HWaE
|
|
QsiPlR4zxP/TP7mhfVEe7XWPxtnMUMtf15OyA51YBM4qBmOHf+MZAAAAIIaTJINn
|
|
+eUBXbki+PSAld2nhJh/LVmFsS+60WyvXkQ1wpsGGBsKAAAALAWCY4d/4wKbDCIh
|
|
BssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce62azJAAAAAAQBIKbpGG2dWTX8
|
|
j+VjFM21J0hqWlEg+bdiojWnKfA5AQpWUWtnNwDEM0g12vYxoWM8Y81W+bHBw805
|
|
I8kWVkXU6vFOi+HWvv/ira7ofJu16NnoUkhclkUrk0mXubZvyl4GBg==
|
|
-----END PGP PUBLIC KEY BLOCK-----` });
|
|
|
|
const signingKeyIDs = message.getSigningKeyIDs();
|
|
expect(key.getKeys(signingKeyIDs[0])).to.not.be.empty;
|
|
|
|
const { data, signatures } = await openpgp.verify({ message, verificationKeys: key });
|
|
expect(signatures).to.have.length(1);
|
|
expect(await signatures[0].verified).to.be.true;
|
|
expect((await signatures[0].signature).packets.length).to.equal(1);
|
|
expect(data.includes('What we need from the grocery store')).to.be.true;
|
|
});
|
|
|
|
it('Verify signed message with two one pass signatures (v3 and v6)', async function() {
|
|
// test vector from gopenpgp
|
|
const message = await openpgp.readMessage({ armoredMessage: `-----BEGIN PGP MESSAGE-----
|
|
|
|
xEYGAAobIBEtnAy3EeX8aDFd2bf/A1Xfi7C/D3mLIkGEwVmD0fecyxhsTwYJppfk
|
|
1S36bHIrDB8eJ8GKVnCPZSXsJ7rZrMkAxA0DAAoW8jFVDE9H444ByxRiAAAAAABI
|
|
ZWxsbyBXb3JsZCA6KcJ1BAAWCgAnBQJk52D2CRDyMVUMT0fjjhYhBOuFu1+jOnXh
|
|
XpROY/IxVQxPR+OOAABOSwEA2nLYxa9ELDxwuPskKCUVs8noyT4fVEScWlWZAKqP
|
|
ykIBAJEhqqNHFP4Gok1Ss9mvf6fE25tJkdJKD+7PIH0mCJgAwpgGABsKAAAAKQUC
|
|
ZOdg9iKhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce62azJAAAAAA2MIBEt
|
|
nAy3EeX8aDFd2bf/A1Xfi7C/D3mLIkGEwVmD0fecr0oTPTcMNupiH7SCY4THe3ue
|
|
7PlRvF2WoeWKkNZT1uwcb+ilW5h9eBpp0I4Xj98C0hMA5+rHsTsME2EZM8HADA==
|
|
-----END PGP MESSAGE-----` });
|
|
const v6Key = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
|
|
|
xioGY4d/4xsAAAAg+U2nu0jWCmHlZ3BqZYfQMxmZu52JGggkLq2EVD34laPCsQYf
|
|
GwoAAABCBYJjh3/jAwsJBwUVCg4IDAIWAAKbAwIeCSIhBssYbE8GCaaX5NUt+mxy
|
|
KwwfHifBilZwj2Ul7Ce62azJBScJAgcCAAAAAK0oIBA+LX0ifsDm185Ecds2v8lw
|
|
gyU2kCcUmKfvBXbAf6rhRYWzuQOwEn7E/aLwIwRaLsdry0+VcallHhSu4RN6HWaE
|
|
QsiPlR4zxP/TP7mhfVEe7XWPxtnMUMtf15OyA51YBM4qBmOHf+MZAAAAIIaTJINn
|
|
+eUBXbki+PSAld2nhJh/LVmFsS+60WyvXkQ1wpsGGBsKAAAALAWCY4d/4wKbDCIh
|
|
BssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce62azJAAAAAAQBIKbpGG2dWTX8
|
|
j+VjFM21J0hqWlEg+bdiojWnKfA5AQpWUWtnNwDEM0g12vYxoWM8Y81W+bHBw805
|
|
I8kWVkXU6vFOi+HWvv/ira7ofJu16NnoUkhclkUrk0mXubZvyl4GBg==
|
|
-----END PGP PUBLIC KEY BLOCK-----` });
|
|
const v4Key = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
|
Comment: Alice's OpenPGP certificate
|
|
|
|
mDMEXEcE6RYJKwYBBAHaRw8BAQdArjWwk3FAqyiFbFBKT4TzXcVBqPTB3gmzlC/U
|
|
b7O1u120JkFsaWNlIExvdmVsYWNlIDxhbGljZUBvcGVucGdwLmV4YW1wbGU+iJAE
|
|
ExYIADgCGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AWIQTrhbtfozp14V6UTmPy
|
|
MVUMT0fjjgUCXaWfOgAKCRDyMVUMT0fjjukrAPoDnHBSogOmsHOsd9qGsiZpgRnO
|
|
dypvbm+QtXZqth9rvwD9HcDC0tC+PHAsO7OTh1S1TC9RiJsvawAfCPaQZoed8gK4
|
|
OARcRwTpEgorBgEEAZdVAQUBAQdAQv8GIa2rSTzgqbXCpDDYMiKRVitCsy203x3s
|
|
E9+eviIDAQgHiHgEGBYIACAWIQTrhbtfozp14V6UTmPyMVUMT0fjjgUCXEcE6QIb
|
|
DAAKCRDyMVUMT0fjjlnQAQDFHUs6TIcxrNTtEZFjUFm1M0PJ1Dng/cDW4xN80fsn
|
|
0QEA22Kr7VkCjeAEC08VSTeV+QFsmz55/lntWkwYWhmvOgE=
|
|
=iIGO
|
|
-----END PGP PUBLIC KEY BLOCK-----` });
|
|
|
|
const { data, signatures } = await openpgp.verify({ message, verificationKeys: [v4Key, v6Key] });
|
|
expect(signatures).to.have.length(2);
|
|
expect(await signatures[0].verified).to.be.true;
|
|
expect((await signatures[0].signature).packets.length).to.equal(1);
|
|
expect(await signatures[1].verified).to.be.true;
|
|
expect((await signatures[1].signature).packets.length).to.equal(1);
|
|
expect(data).to.equal('Hello World :)');
|
|
});
|
|
|
|
it('Verify signed message with two one pass signatures (both v3)', async function() {
|
|
const msg_armor =
|
|
['-----BEGIN PGP MESSAGE-----',
|
|
'Version: GnuPG v2.0.19 (GNU/Linux)',
|
|
'',
|
|
'owGbwMvMwMF4+5Pyi4Jg3y8ME8DcBy3fXXIUdKYzrjFNYilJrSgJmsXDXJyRX1Si',
|
|
'kJtaXJyYnsqVBxRVyMnMS+V6O3XOq61r30zbov9m4YY3LQteL5/QMYeFgZGDgY2V',
|
|
'CaSRgYtTAGZiYxYLwySbQk07ptZel6gmjrKyBWsyWdkOG3oscLBdIpXXfDdb6fNv',
|
|
'8ULN5L1ed+xNo79P2dBotWud6vn7e9dtLJ7o12PunnvEz8gyyvP4/As/los0xsnZ',
|
|
'H+8ublrhvGtLxJUZuUKZO6QdHq2Nepuw8OrfiMXPBDQXXpV2q11Ze+rD3lndgv/C',
|
|
'bJQNOhll0J0H839jFvt/16m20h/ZmDoWqJywapnypjdIjcXr+7rJFess40yenV7Q',
|
|
'2LSu/EX6Aq29x+dv+GPUMfuhTNE3viWWUR4PD6T7XfmdViUwmSf8fkRNUn/t3a2n',
|
|
'cq46Xr36seCor/OLp0atSZwHrjx2SU5zPLheZn+zw/0d1/YZnD7AEeP9s/Cuycyv',
|
|
'CZ5HZNKufvB8fsh+dfdSXW0GfqkPfxk36Vw8ufpjaoZDyt2nxxg/6D4KS3UvZzv3',
|
|
'axdLZ9yd0OJNZv4P501If24W4vTGz6nI7Ser8Yd2PiOvE5MWMT0wLZQ+zPX1sv0/',
|
|
's8PvkyWmVM0O0fB/ZSHovHNNPffDg/rWhzOmXQ9/7vTn477F+aWm5sYzJ75/BQA=',
|
|
'=+L0S',
|
|
'-----END PGP MESSAGE-----'].join('\n');
|
|
const plaintext = 'short message\nnext line\n한국어/조선말';
|
|
const sMsg = await openpgp.readMessage({ armoredMessage: msg_armor });
|
|
const pubKey2 = await openpgp.readKey({ armoredKey: pub_key_arm2 });
|
|
const pubKey3 = await openpgp.readKey({ armoredKey: pub_key_arm3 });
|
|
|
|
const keyIDs = sMsg.getSigningKeyIDs();
|
|
expect(pubKey2.getKeys(keyIDs[1])).to.not.be.empty;
|
|
expect(pubKey3.getKeys(keyIDs[0])).to.not.be.empty;
|
|
|
|
const { data, signatures } = await openpgp.verify({ message: sMsg, verificationKeys: [pubKey2, pubKey3], config: { minRSABits: 1024 } });
|
|
expect(data).to.equal(plaintext);
|
|
expect(signatures).to.exist;
|
|
expect(signatures).to.have.length(2);
|
|
expect(await signatures[0].verified).to.be.true;
|
|
expect(await signatures[1].verified).to.be.true;
|
|
expect((await signatures[0].signature).packets.length).to.equal(1);
|
|
expect((await signatures[1].signature).packets.length).to.equal(1);
|
|
});
|
|
|
|
it('Verify fails with signed message with critical notations', async function() {
|
|
const message = await openpgp.readMessage({ armoredMessage: signature_with_critical_notation });
|
|
const key = await openpgp.readKey({ armoredKey: pub_key_arm2 });
|
|
const { signatures: [sig] } = await openpgp.verify({ message, verificationKeys: key, config: { minRSABits: 1024 } });
|
|
await expect(sig.verified).to.be.rejectedWith(/Unknown critical notation: test@example.com/);
|
|
});
|
|
|
|
it('Verify succeeds with known signed message with critical notations', async function() {
|
|
const message = await openpgp.readMessage({ armoredMessage: signature_with_critical_notation });
|
|
const key = await openpgp.readKey({ armoredKey: pub_key_arm2 });
|
|
|
|
const config = { knownNotations: ['test@example.com'], minRSABits: 1024 };
|
|
const { signatures: [sig] } = await openpgp.verify({ message, verificationKeys: key, config });
|
|
expect(await sig.verified).to.be.true;
|
|
});
|
|
|
|
it('Can create notations', async function() {
|
|
const privKey = await openpgp.decryptKey({
|
|
privateKey: await openpgp.readKey({ armoredKey: priv_key_arm2 }),
|
|
passphrase: 'hello world'
|
|
});
|
|
|
|
const config = { minRSABits: 1024 };
|
|
const message_with_notation = await openpgp.encrypt({
|
|
message: await openpgp.createMessage({ text: 'test' }),
|
|
encryptionKeys: privKey,
|
|
signingKeys: privKey,
|
|
signatureNotations: [
|
|
{
|
|
name: 'test@example.com',
|
|
value: new TextEncoder().encode('test'),
|
|
humanReadable: true,
|
|
critical: true
|
|
},
|
|
{
|
|
name: 'séparation-de-domaine@proton.ch',
|
|
value: new Uint8Array([0, 1, 2, 3]),
|
|
humanReadable: false,
|
|
critical: false
|
|
}
|
|
],
|
|
config
|
|
});
|
|
await expect(openpgp.decrypt({
|
|
message: await openpgp.readMessage({ armoredMessage: message_with_notation }),
|
|
decryptionKeys: privKey,
|
|
verificationKeys: privKey,
|
|
expectSigned: true,
|
|
config
|
|
})).to.be.rejectedWith('Unknown critical notation: test@example.com');
|
|
const { signatures: [sig] } = await openpgp.decrypt({
|
|
message: await openpgp.readMessage({ armoredMessage: message_with_notation }),
|
|
decryptionKeys: privKey,
|
|
verificationKeys: privKey,
|
|
config: {
|
|
knownNotations: ['test@example.com'],
|
|
...config
|
|
}
|
|
});
|
|
expect(await sig.verified).to.be.true;
|
|
const { packets: [{ rawNotations: notations }] } = await sig.signature;
|
|
expect(notations).to.have.length(3);
|
|
expect(notations[0].name).to.equal('test@example.com');
|
|
expect(notations[0].value).to.deep.equal(new Uint8Array([116, 101, 115, 116]));
|
|
expect(notations[0].humanReadable).to.be.true;
|
|
expect(notations[0].critical).to.be.true;
|
|
expect(notations[1].name).to.equal('séparation-de-domaine@proton.ch');
|
|
expect(notations[1].value).to.deep.equal(new Uint8Array([0, 1, 2, 3]));
|
|
expect(notations[1].humanReadable).to.be.false;
|
|
expect(notations[1].critical).to.be.false;
|
|
expect(notations[2].name).to.equal('salt@notations.openpgpjs.org');
|
|
expect(notations[2].humanReadable).to.be.false;
|
|
expect(notations[2].critical).to.be.false;
|
|
});
|
|
|
|
it('v4 signatures are randomized via salt notation (`config.nonDeterministicSignaturesViaNotation`)', async function() {
|
|
const v4SigningKey = await openpgp.readKey({
|
|
armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
|
|
|
xVgEX8+jfBYJKwYBBAHaRw8BAQdA9GbdDjprR0sWf0R5a5IpulUauc0FsmzJ
|
|
mOYCfoowt8EAAP9UwaqC0LWWQ5RlX7mps3728vFa/If1KBVwAjk7Uqhi2BKL
|
|
zQ90ZXN0MiA8YkBhLmNvbT7CjAQQFgoAHQUCX8+jfAQLCQcIAxUICgQWAgEA
|
|
AhkBAhsDAh4BACEJEG464aV2od77FiEEIcg441MtKnyJnPDRbjrhpXah3vuR
|
|
gQD+Il6Gw2oIok4/ANyDDLBYZtKqRrMv4NcfF9DHYuAFcP4BAPhFOffyP3qU
|
|
AEZb7QPrWdLfhn8/FeSFZxJvnmupQ9sDx10EX8+jfBIKKwYBBAGXVQEFAQEH
|
|
QOSzo9cX1U2esGFClprOt0QWXNJ97228R5tKFxo6/0NoAwEIBwAA/0n4sq2i
|
|
N6/jE+6rVO4o/7LW0xahxpV1tTA6qv1Op9TwFIDCeAQYFggACQUCX8+jfAIb
|
|
DAAhCRBuOuGldqHe+xYhBCHIOONTLSp8iZzw0W464aV2od773XcA/jlmX8/c
|
|
1/zIotEkyMZB4mI+GAg3FQ6bIACFBH1sz0MzAP9Snri0P4FRZ8D5THRCJoUm
|
|
GBgpBmrf6IVv484jBswGDA==
|
|
=8rBO
|
|
-----END PGP PRIVATE KEY BLOCK-----`
|
|
});
|
|
|
|
const date = new Date('Tue, 25 Dec 2023 00:00:00 GMT');
|
|
const text = 'test';
|
|
const armoredRandomSignature1 = await openpgp.sign({
|
|
message: await openpgp.createMessage({ text }),
|
|
signingKeys: v4SigningKey,
|
|
date,
|
|
detached: true
|
|
});
|
|
const armoredRandomSignature2 = await openpgp.sign({
|
|
message: await openpgp.createMessage({ text }),
|
|
signingKeys: v4SigningKey,
|
|
date,
|
|
detached: true
|
|
});
|
|
const randomSignature1 = await openpgp.readSignature({ armoredSignature: armoredRandomSignature1 });
|
|
const randomSignature2 = await openpgp.readSignature({ armoredSignature: armoredRandomSignature2 });
|
|
expect(randomSignature1.packets[0].signedHashValue).to.not.deep.equal(randomSignature2.packets[0].signedHashValue);
|
|
|
|
// ensure the signatures are verifiable, as a sanity check
|
|
const verification1 = await openpgp.verify({ message: await openpgp.createMessage({ text }), signature: randomSignature1, verificationKeys: v4SigningKey, expectSigned: true });
|
|
expect(verification1.data).to.equal(text);
|
|
|
|
const armoredDeterministicSignature1 = await openpgp.sign({
|
|
message: await openpgp.createMessage({ text }),
|
|
signingKeys: v4SigningKey,
|
|
date,
|
|
detached: true,
|
|
config: { nonDeterministicSignaturesViaNotation: false }
|
|
});
|
|
const armoredDeterministicSignature2 = await openpgp.sign({
|
|
message: await openpgp.createMessage({ text }),
|
|
signingKeys: v4SigningKey,
|
|
date,
|
|
detached: true,
|
|
config: { nonDeterministicSignaturesViaNotation: false }
|
|
});
|
|
const deterministicSignature1 = await openpgp.readSignature({ armoredSignature: armoredDeterministicSignature1 });
|
|
const deterministicSignature2 = await openpgp.readSignature({ armoredSignature: armoredDeterministicSignature2 });
|
|
expect(deterministicSignature1.packets[0].signedHashValue).to.deep.equal(deterministicSignature2.packets[0].signedHashValue);
|
|
const verification2 = await openpgp.verify({ message: await openpgp.createMessage({ text }), signature: deterministicSignature1, verificationKeys: v4SigningKey, expectSigned: true });
|
|
expect(verification2.data).to.equal(text);
|
|
});
|
|
|
|
it('Verify v6 cleartext signed message with openpgp.verify', async function() {
|
|
// test vector from https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-08.html#name-sample-v6-certificate-trans
|
|
const cleartextMessage = `-----BEGIN PGP SIGNED MESSAGE-----
|
|
|
|
What we need from the grocery store:
|
|
|
|
- - tofu
|
|
- - vegetables
|
|
- - noodles
|
|
|
|
-----BEGIN PGP SIGNATURE-----
|
|
|
|
wpgGARsKAAAAKQWCY5ijYyIhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce6
|
|
2azJAAAAAGk2IHZJX1AhiJD39eLuPBgiUU9wUA9VHYblySHkBONKU/usJ9BvuAqo
|
|
/FvLFuGWMbKAdA+epq7V4HOtAPlBWmU8QOd6aud+aSunHQaaEJ+iTFjP2OMW0KBr
|
|
NK2ay45cX1IVAQ==
|
|
-----END PGP SIGNATURE-----`;
|
|
|
|
const publicKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
|
|
|
xioGY4d/4xsAAAAg+U2nu0jWCmHlZ3BqZYfQMxmZu52JGggkLq2EVD34laPCsQYf
|
|
GwoAAABCBYJjh3/jAwsJBwUVCg4IDAIWAAKbAwIeCSIhBssYbE8GCaaX5NUt+mxy
|
|
KwwfHifBilZwj2Ul7Ce62azJBScJAgcCAAAAAK0oIBA+LX0ifsDm185Ecds2v8lw
|
|
gyU2kCcUmKfvBXbAf6rhRYWzuQOwEn7E/aLwIwRaLsdry0+VcallHhSu4RN6HWaE
|
|
QsiPlR4zxP/TP7mhfVEe7XWPxtnMUMtf15OyA51YBM4qBmOHf+MZAAAAIIaTJINn
|
|
+eUBXbki+PSAld2nhJh/LVmFsS+60WyvXkQ1wpsGGBsKAAAALAWCY4d/4wKbDCIh
|
|
BssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce62azJAAAAAAQBIKbpGG2dWTX8
|
|
j+VjFM21J0hqWlEg+bdiojWnKfA5AQpWUWtnNwDEM0g12vYxoWM8Y81W+bHBw805
|
|
I8kWVkXU6vFOi+HWvv/ira7ofJu16NnoUkhclkUrk0mXubZvyl4GBg==
|
|
-----END PGP PUBLIC KEY BLOCK-----` });
|
|
|
|
const plaintext = 'What we need from the grocery store:\n\n- tofu\n- vegetables\n- noodles\n';
|
|
const message = await openpgp.readCleartextMessage({ cleartextMessage });
|
|
|
|
const { signatures, data } = await openpgp.verify({ message, verificationKeys: publicKey });
|
|
expect(data).to.equal(plaintext);
|
|
expect(signatures).to.have.length(1);
|
|
expect(await signatures[0].verified).to.be.true;
|
|
expect((await signatures[0].signature).packets.length).to.equal(1);
|
|
});
|
|
|
|
it('Verify cleartext signed message with two signatures with openpgp.verify', async function() {
|
|
const cleartextMessage =
|
|
['-----BEGIN PGP SIGNED MESSAGE-----',
|
|
'Hash: SHA256',
|
|
'',
|
|
'short message',
|
|
'next line',
|
|
'한국어/조선말',
|
|
'-----BEGIN PGP SIGNATURE-----',
|
|
'Version: GnuPG v2.0.19 (GNU/Linux)',
|
|
'',
|
|
'iJwEAQEIAAYFAlKcju8ACgkQ4IT3RGwgLJci6gP/dCmIraUa6AGpJxzGfK+jYpjl',
|
|
'G0KunFyGmyPxeJVnPi2bBp3EPIbiayQ71CcDe9DKpF046tora07AA9eo+/YbvJ9P',
|
|
'PWeScw3oj/ejsmKQoDBGzyDMFUphevnhgc5lENjovJqmiu6FKjNmADTxcZ/qFTOq',
|
|
'44EWTgdW3IqXFkNpKjeJARwEAQEIAAYFAlKcju8ACgkQ2/Ij6HBTTfQi6gf9HxhE',
|
|
'ycLDhQ8iyC090TaYwsDytScU2vOMiI5rJCy2tfDV0pfn+UekYGMnKxZTpwtmno1j',
|
|
'mVOlieENszz5IcehS5TYwk4lmRFjoba+Z8qwPEYhYxP29GMbmRIsH811sQHFTigo',
|
|
'LI2t4pSSSUpAiXd9y6KtvkWcGGn8IfkNHCEHPh1ov28QvH0+ByIiKYK5N6ZB8hEo',
|
|
'0uMYhKQPVJdPCvMkAxQCRPw84EvmxuJ0HMCeSB9tHQXpz5un2m8D9yiGpBQPnqlW',
|
|
'vCCq7fgaUz8ksxvQ9bSwv0iIIbbBdTP7Z8y2c1Oof6NDl7irH+QCeNT7IIGs8Smn',
|
|
'BEzv/FqkQAhjy3Krxg==',
|
|
'=3Pkl',
|
|
'-----END PGP SIGNATURE-----'].join('\n');
|
|
|
|
const plaintext = 'short message\nnext line\n한국어/조선말';
|
|
const message = await openpgp.readCleartextMessage({ cleartextMessage });
|
|
const pubKey2 = await openpgp.readKey({ armoredKey: pub_key_arm2 });
|
|
const pubKey3 = await openpgp.readKey({ armoredKey: pub_key_arm3 });
|
|
|
|
const keyIDs = message.getSigningKeyIDs();
|
|
|
|
expect(pubKey2.getKeys(keyIDs[0])).to.not.be.empty;
|
|
expect(pubKey3.getKeys(keyIDs[1])).to.not.be.empty;
|
|
|
|
return openpgp.verify({ verificationKeys:[pubKey2, pubKey3], message, config: { minRSABits: 1024 } }).then(async function({ signatures, data }) {
|
|
expect(data).to.equal(plaintext);
|
|
expect(signatures).to.have.length(2);
|
|
expect(await signatures[0].verified).to.be.true;
|
|
expect(await signatures[1].verified).to.be.true;
|
|
expect((await signatures[0].signature).packets.length).to.equal(1);
|
|
expect((await signatures[1].signature).packets.length).to.equal(1);
|
|
});
|
|
});
|
|
|
|
it('Verify latin-1 signed message', async function() {
|
|
const latin1Binary = util.hexToUint8Array('48e46c6cf62057e86c74');
|
|
const message = await openpgp.createMessage({ binary: latin1Binary });
|
|
|
|
message.appendSignature(`-----BEGIN PGP SIGNATURE-----
|
|
|
|
iQIzBAEBCAAdFiEET5+J9VBawdGiYGMc2xGHud1faTsFAl5lE/AACgkQ2xGHud1f
|
|
aTtIuw//YWrVaXLyP8sGBc0uUSLxQbmfQQYV8Oq8Vsg+jV4orc73wmEy8+Nj5m2g
|
|
fFEPaWy07dfDBtv874XCsZmCM+ZhwkGaT9lwcCxkxNZeywTE5JRS1/6Ky3G4gDZ/
|
|
QozTXr/ZNPXF6bBENqhfqeO2xkD577bjiPu5wLcu3/RR39YnWp5zQu9ynJbpwobz
|
|
HHQW5TgSUgi/9tInQ+cc7vMkHzfe2Zg45HkyaStBW1x7Fm9FLv8GNw1R2jVbUlsX
|
|
SEL7yPrsZAmgyu1ifMrTTY4vunuUNUFiGZN9UC75b7s4tjKkvJ0sfdQusC0vmcE0
|
|
Wq7dAoeX72B94TITuXldDGIfL01smycm+mEvf/kXxQg81wj4la72IzhdWeC6r4PF
|
|
558QDEtZy984iL8RJKpbjwgsxyvfM9zf9qtmuNdscbZaZsx9LRe21uaKhX8yJsAU
|
|
jCgyjM5e7CMdvBUyxrpGzS+mP/rh77r2TXkg6u2+8Nj4osxwkfxvDIGpJfaIWl2a
|
|
sNQ4Bsgm6rcNYaxUVbOsBFJddBb503KpTX5aK8TuC6AINg6bV6rmfj2Jc/QX4eHb
|
|
Xgm6EyJo74z5R7YvA3XdUZf1sfwfoMLbbUqpeHEZOcWy4vrS79Omx1MyPxKHPiXU
|
|
PAAeuQTUrcJdZeJ86eQ9cCUB216HCwSKOWTQRzL+hBWKXij4WD4=
|
|
=ZEFm
|
|
-----END PGP SIGNATURE-----`);
|
|
|
|
const pubKey = await openpgp.readKey({ armoredKey: pub_latin1_msg });
|
|
|
|
return message.verify([pubKey]).then(async verifiedSig => {
|
|
expect(await stream.readToEnd(message.getLiteralData())).to.equal(latin1Binary);
|
|
expect(verifiedSig).to.exist;
|
|
expect(verifiedSig).to.have.length(1);
|
|
expect(await verifiedSig[0].verified).to.be.true;
|
|
expect((await verifiedSig[0].signature).packets.length).to.equal(1);
|
|
});
|
|
});
|
|
|
|
|
|
it('Verify cleartext signed message with trailing spaces from GPG', async function() {
|
|
const cleartextMessage =
|
|
`-----BEGIN PGP SIGNED MESSAGE-----
|
|
Hash: SHA1
|
|
|
|
space:
|
|
space and tab: \t
|
|
no trailing space
|
|
|
|
tab:\t
|
|
tab and space:\t
|
|
-----BEGIN PGP SIGNATURE-----
|
|
Version: GnuPG v1
|
|
|
|
iJwEAQECAAYFAlrZzCQACgkQ4IT3RGwgLJeWggP+Pb33ubbELIzg9/imM+zlR063
|
|
g0FbG4B+RGZNFSbaDArUgh9fdVqBy8M9vvbbDMBalSiQxY09Lrasfb+tsomrygbN
|
|
NisuPRa5phPhn1bB4hZDb2ed/iK41CNyU7QHuv4AAvLC0mMamRnEg0FW2M2jZLGh
|
|
zmuVOdNuWQqxT9Sqa84=
|
|
=bqAR
|
|
-----END PGP SIGNATURE-----`;
|
|
|
|
const plaintext = 'space: \nspace and tab: \t\nno trailing space\n \ntab:\t\ntab and space:\t ';
|
|
const message = await openpgp.readCleartextMessage({ cleartextMessage });
|
|
const pubKey = await openpgp.readKey({ armoredKey: pub_key_arm2 });
|
|
|
|
const keyIDs = message.getSigningKeyIDs();
|
|
|
|
expect(pubKey.getKeys(keyIDs[0])).to.not.be.empty;
|
|
|
|
const { signatures, data } = await openpgp.verify({
|
|
verificationKeys:[pubKey],
|
|
message,
|
|
config: { minRSABits: 1024, rejectMessageHashAlgorithms: new Set() }
|
|
});
|
|
expect(data).to.equal(plaintext.replace(/[ \t]+$/mg, ''));
|
|
expect(signatures).to.have.length(1);
|
|
expect(await signatures[0].verified).to.be.true;
|
|
expect((await signatures[0].signature).packets.length).to.equal(1);
|
|
});
|
|
|
|
it('Verify cleartext signed message with trailing spaces incorrectly normalised (from OpenPGP.js v3.0.9-v5.3.1)', async function() {
|
|
// We used to not strip trailing whitespace with \r\n line endings when signing cleartext messages
|
|
const armoredSignature = `-----BEGIN PGP SIGNATURE-----
|
|
Version: OpenPGP.js v5.3.1
|
|
|
|
wrMEAQEIAAYFAmLjqsQAIQkQ4IT3RGwgLJcWIQTX0bHexsqUZwA0RcXghPdE
|
|
bCAsl2TvBADLOHYXevDSc3LtLRYR1HteijL/MssCCoZIfuGihd5AzJpD2h2j
|
|
L8UuxlfERJn15RlFsDzlkMNMefJp5ltC8kKcf+HTuBUi+xf2t2nvlf8CrdjY
|
|
vcEqswjkODDxxZ842h0sC0ZtbzWuMXIvODEdzZxBjhlmZmv9VKQ5uyb0oD/5
|
|
WQ==
|
|
=o2gq
|
|
-----END PGP SIGNATURE-----`;
|
|
const cleartextMessage = `
|
|
-----BEGIN PGP SIGNED MESSAGE-----
|
|
Hash: SHA256
|
|
|
|
this text
|
|
used to be incorrectly normalised
|
|
${armoredSignature}
|
|
`;
|
|
|
|
const signedText = 'this text \r\nused to be incorrectly normalised';
|
|
const message = await openpgp.readCleartextMessage({ cleartextMessage });
|
|
const pubKey = await openpgp.readKey({ armoredKey: pub_key_arm2 });
|
|
|
|
// Direct verification won't work since the signed data was not stripped of the trailing whitespaces,
|
|
// as required for cleartext messages. Verification would always fail also in the affected OpenPGP.js versions.
|
|
await expect(openpgp.verify({
|
|
verificationKeys:[pubKey],
|
|
message,
|
|
config: { minRSABits: 1024 },
|
|
expectSigned: true
|
|
})).to.be.rejectedWith(/Signed digest did not match/);
|
|
|
|
// The signature should be verifiable over non-normalised text
|
|
const { signatures, data } = await openpgp.verify({
|
|
verificationKeys:[pubKey],
|
|
message: await openpgp.createMessage({ text: signedText }),
|
|
signature: await openpgp.readSignature({ armoredSignature }),
|
|
config: { minRSABits: 1024 },
|
|
expectSigned: true
|
|
});
|
|
expect(data).to.equal(signedText);
|
|
expect(signatures).to.have.length(1);
|
|
expect(await signatures[0].verified).to.be.true;
|
|
});
|
|
|
|
it('Sign and verify cleartext signed message with trailing spaces correctly normalised', async function() {
|
|
const pubKey = await openpgp.readKey({ armoredKey: pub_key_arm2 });
|
|
const privKey = await openpgp.decryptKey({
|
|
privateKey: await openpgp.readKey({ armoredKey: priv_key_arm2 }),
|
|
passphrase: 'hello world'
|
|
});
|
|
const config = { minRSABits: 1024 };
|
|
|
|
const message = await openpgp.createCleartextMessage({
|
|
text: 'this text \r\nused to be incorrectly normalised'
|
|
});
|
|
const expectedText = 'this text\nused to be incorrectly normalised';
|
|
expect(message.getText()).to.equal(expectedText);
|
|
const cleartextMessage = await openpgp.sign({ message, signingKeys: privKey, config, format: 'armored' });
|
|
const { signatures, data } = await openpgp.verify({
|
|
message: await openpgp.readCleartextMessage({ cleartextMessage }),
|
|
verificationKeys:[pubKey],
|
|
config
|
|
});
|
|
expect(data).to.equal(expectedText);
|
|
expect(signatures).to.have.length(1);
|
|
expect(await signatures[0].verified).to.be.true;
|
|
});
|
|
|
|
it('Does not emit headers for v6 cleartext message', async function() {
|
|
const v6PrivateKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
|
|
|
xUsGY4d/4xsAAAAg+U2nu0jWCmHlZ3BqZYfQMxmZu52JGggkLq2EVD34laMAGXKB
|
|
exK+cH6NX1hs5hNhIB00TrJmosgv3mg1ditlsLfCsQYfGwoAAABCBYJjh3/jAwsJ
|
|
BwUVCg4IDAIWAAKbAwIeCSIhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce6
|
|
2azJBScJAgcCAAAAAK0oIBA+LX0ifsDm185Ecds2v8lwgyU2kCcUmKfvBXbAf6rh
|
|
RYWzuQOwEn7E/aLwIwRaLsdry0+VcallHhSu4RN6HWaEQsiPlR4zxP/TP7mhfVEe
|
|
7XWPxtnMUMtf15OyA51YBMdLBmOHf+MZAAAAIIaTJINn+eUBXbki+PSAld2nhJh/
|
|
LVmFsS+60WyvXkQ1AE1gCk95TUR3XFeibg/u/tVY6a//1q0NWC1X+yui3O24wpsG
|
|
GBsKAAAALAWCY4d/4wKbDCIhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce6
|
|
2azJAAAAAAQBIKbpGG2dWTX8j+VjFM21J0hqWlEg+bdiojWnKfA5AQpWUWtnNwDE
|
|
M0g12vYxoWM8Y81W+bHBw805I8kWVkXU6vFOi+HWvv/ira7ofJu16NnoUkhclkUr
|
|
k0mXubZvyl4GBg==
|
|
-----END PGP PRIVATE KEY BLOCK-----` });
|
|
const v4PrivateKey = await openpgp.decryptKey({
|
|
privateKey: await openpgp.readKey({ armoredKey: priv_key_arm2 }),
|
|
passphrase: 'hello world'
|
|
});
|
|
|
|
const message = await openpgp.createCleartextMessage({ text: 'check header message' });
|
|
|
|
const cleartextMessageV6 = await openpgp.sign({ message, signingKeys: v6PrivateKey });
|
|
const cleartextMessageV4 = await openpgp.sign({
|
|
message,
|
|
signingKeys: [v4PrivateKey, v6PrivateKey],
|
|
config: { minRSABits: 1024 }
|
|
});
|
|
expect(cleartextMessageV6).to.not.contain('Hash:');
|
|
expect(cleartextMessageV4).to.contain('Hash:');
|
|
});
|
|
|
|
function tests() {
|
|
it('Verify signed message with trailing spaces from GPG', async function() {
|
|
const armoredMessage =
|
|
`-----BEGIN PGP MESSAGE-----
|
|
Version: GnuPG v1
|
|
|
|
owGbwMvMyMT4oOW7S46CznTG01El3MUFicmpxbolqcUlUTev14K5Vgq8XGCGQmJe
|
|
ikJJYpKVAicvV16+QklRYmZOZl66AliWl0sBqBAkzQmmwKohBnAqdMxhYWRkYmBj
|
|
ZQIZy8DFKQCztusM8z+Vt/svG80IS/etn90utv/T16jquk69zPvp6t9F16ryrwpb
|
|
kfVlS5Xl38KnVYxWvIor0nao6WUczA4vvZX9TXPWnnW3tt1vbZoiqWUjYjjjhuKG
|
|
4DtmMTuL3TW6/zNzVfWp/Q11+71O8RGnXMsBvWM6mSqX75uLiPo6HRaUDHnvrfCP
|
|
yYDnCgA=
|
|
=15ki
|
|
-----END PGP MESSAGE-----`;
|
|
|
|
const plaintext = 'space: \nspace and tab: \t\nno trailing space\n \ntab:\t\ntab and space:\t ';
|
|
const message = await openpgp.readMessage({ armoredMessage });
|
|
const pubKey = await openpgp.readKey({ armoredKey: pub_key_arm2 });
|
|
|
|
const keyIDs = message.getSigningKeyIDs();
|
|
expect(pubKey.getKeys(keyIDs[0])).to.not.be.empty;
|
|
|
|
return openpgp.verify({ verificationKeys: [pubKey], message, config: { minRSABits: 1024 } }).then(async ({ data, signatures }) => {
|
|
expect(data).to.equal(plaintext);
|
|
expect(signatures).to.have.length(1);
|
|
if (openpgp.config.rejectMessageHashAlgorithms.has(openpgp.enums.hash.sha1)) {
|
|
await expect(signatures[0].verified).to.be.rejected;
|
|
} else {
|
|
expect(await signatures[0].verified).to.be.true;
|
|
}
|
|
expect((await signatures[0].signature).packets.length).to.equal(1);
|
|
});
|
|
});
|
|
|
|
it('Streaming verify signed message with trailing spaces from GPG', async function() {
|
|
const armoredMessage =
|
|
`-----BEGIN PGP MESSAGE-----
|
|
Version: GnuPG v1
|
|
|
|
owGbwMvMyMT4oOW7S46CznTG01El3MUFicmpxbolqcUlUTev14K5Vgq8XGCGQmJe
|
|
ikJJYpKVAicvV16+QklRYmZOZl66AliWl0sBqBAkzQmmwKohBnAqdMxhYWRkYmBj
|
|
ZQIZy8DFKQCztusM8z+Vt/svG80IS/etn90utv/T16jquk69zPvp6t9F16ryrwpb
|
|
kfVlS5Xl38KnVYxWvIor0nao6WUczA4vvZX9TXPWnnW3tt1vbZoiqWUjYjjjhuKG
|
|
4DtmMTuL3TW6/zNzVfWp/Q11+71O8RGnXMsBvWM6mSqX75uLiPo6HRaUDHnvrfCP
|
|
yYDnCgA=
|
|
=15ki
|
|
-----END PGP MESSAGE-----`.split('');
|
|
|
|
const plaintext = 'space: \nspace and tab: \t\nno trailing space\n \ntab:\t\ntab and space:\t ';
|
|
await loadStreamsPolyfill();
|
|
const message = await openpgp.readMessage({
|
|
armoredMessage: new ReadableStream({
|
|
async pull(controller) {
|
|
await new Promise(setTimeout);
|
|
controller.enqueue(armoredMessage.shift());
|
|
if (!armoredMessage.length) controller.close();
|
|
}
|
|
})
|
|
});
|
|
const pubKey = await openpgp.readKey({ armoredKey: pub_key_arm2 });
|
|
|
|
const keyIDs = message.getSigningKeyIDs();
|
|
expect(pubKey.getKeys(keyIDs[0])).to.not.be.empty;
|
|
|
|
return openpgp.verify({ verificationKeys: [pubKey], message, config: { minRSABits: 1024 } }).then(async function(cleartextSig) {
|
|
expect(cleartextSig).to.exist;
|
|
expect(await stream.readToEnd(cleartextSig.data)).to.equal(plaintext);
|
|
expect(cleartextSig.signatures).to.have.length(1);
|
|
if (!openpgp.config.rejectMessageHashAlgorithms.has(openpgp.enums.hash.sha1)) {
|
|
expect(await cleartextSig.signatures[0].verified).to.be.true;
|
|
} else {
|
|
await expect(cleartextSig.signatures[0].verified).to.be.rejectedWith('Insecure message hash algorithm: SHA1');
|
|
}
|
|
expect((await cleartextSig.signatures[0].signature).packets.length).to.equal(1);
|
|
});
|
|
});
|
|
|
|
it('Verify signed message with missing signature packet', async function() {
|
|
const armoredMessage =
|
|
`-----BEGIN PGP MESSAGE-----
|
|
Version: OpenPGP.js v3.1.3
|
|
Comment: https://openpgpjs.org
|
|
|
|
yFgBO8LLzMjE+KDlu0uOgs50xtNRJdzFBYnJqcW6JanFJVE3r9eCuVYKvFxg
|
|
hkJiXopCSWKSlQInL1devkJJUWJmTmZeugJYlpdLAagQJM0JpsCqIQZwKgAA
|
|
|
|
=D6TZ
|
|
-----END PGP MESSAGE-----`;
|
|
|
|
const plaintext = 'space: \nspace and tab: \t\nno trailing space\n \ntab:\t\ntab and space:\t ';
|
|
const message = await openpgp.readMessage({ armoredMessage });
|
|
const pubKey = await openpgp.readKey({ armoredKey: pub_key_arm2 });
|
|
|
|
const keyIDs = message.getSigningKeyIDs();
|
|
expect(pubKey.getKeys(keyIDs[0])).to.not.be.empty;
|
|
|
|
return openpgp.verify({ verificationKeys: [pubKey], message, config: { minRSABits: 1024 } }).then(async ({ data, signatures }) => {
|
|
expect(data).to.equal(plaintext);
|
|
expect(signatures).to.have.length(0);
|
|
});
|
|
});
|
|
|
|
it('Streaming verify signed message with missing signature packet', async function() {
|
|
const armoredMessage =
|
|
`-----BEGIN PGP MESSAGE-----
|
|
Version: OpenPGP.js v3.1.3
|
|
Comment: https://openpgpjs.org
|
|
|
|
yFgBO8LLzMjE+KDlu0uOgs50xtNRJdzFBYnJqcW6JanFJVE3r9eCuVYKvFxg
|
|
hkJiXopCSWKSlQInL1devkJJUWJmTmZeugJYlpdLAagQJM0JpsCqIQZwKgAA
|
|
|
|
=D6TZ
|
|
-----END PGP MESSAGE-----`.split('');
|
|
|
|
const plaintext = 'space: \nspace and tab: \t\nno trailing space\n \ntab:\t\ntab and space:\t ';
|
|
await loadStreamsPolyfill();
|
|
const message = await openpgp.readMessage({
|
|
armoredMessage: new ReadableStream({
|
|
async pull(controller) {
|
|
await new Promise(setTimeout);
|
|
controller.enqueue(armoredMessage.shift());
|
|
if (!armoredMessage.length) controller.close();
|
|
}
|
|
})
|
|
});
|
|
const pubKey = await openpgp.readKey({ armoredKey: pub_key_arm2 });
|
|
|
|
const keyIDs = message.getSigningKeyIDs();
|
|
expect(pubKey.getKeys(keyIDs[0])).to.not.be.empty;
|
|
|
|
return openpgp.verify({ verificationKeys: [pubKey], message, config: { minRSABits: 1024 } }).then(async ({ data, signatures }) => {
|
|
expect(await stream.readToEnd(data)).to.equal(plaintext);
|
|
expect(signatures).to.have.length(1);
|
|
await expect(signatures[0].verified).to.be.rejectedWith('Corresponding signature packet missing');
|
|
expect((await signatures[0].signature).packets.length).to.equal(0);
|
|
});
|
|
});
|
|
}
|
|
|
|
tests();
|
|
|
|
let rejectMessageHashAlgorithms;
|
|
tryTests('Accept SHA-1 signatures', tests, {
|
|
if: true,
|
|
before: function() {
|
|
({ rejectMessageHashAlgorithms } = openpgp.config);
|
|
Object.assign(openpgp.config, { rejectMessageHashAlgorithms: new Set([openpgp.enums.hash.md5, openpgp.enums.hash.ripemd]) });
|
|
},
|
|
after: function() {
|
|
Object.assign(openpgp.config, { rejectMessageHashAlgorithms });
|
|
}
|
|
});
|
|
|
|
it('Sign text with openpgp.sign and verify with openpgp.verify leads to same string cleartext and valid signatures', async function() {
|
|
const plaintext = 'short message\nnext line \n한국어/조선말';
|
|
const pubKey = await openpgp.readKey({ armoredKey: pub_key_arm2 });
|
|
const privKey = await openpgp.decryptKey({
|
|
privateKey: await openpgp.readKey({ armoredKey: priv_key_arm2 }),
|
|
passphrase: 'hello world'
|
|
});
|
|
|
|
const config = { minRSABits: 1024 };
|
|
return openpgp.sign({ signingKeys: privKey, message: await openpgp.createCleartextMessage({ text: plaintext }), config }).then(async signed => {
|
|
|
|
const message = await openpgp.readCleartextMessage({ cleartextMessage: signed });
|
|
return openpgp.verify({ verificationKeys:[pubKey], message, config });
|
|
|
|
}).then(async function({ data, signatures }) {
|
|
expect(data).to.equal(plaintext.replace(/[ \t\r]+$/mg, ''));
|
|
expect(signatures).to.have.length(1);
|
|
expect(await signatures[0].verified).to.be.true;
|
|
expect((await signatures[0].signature).packets.length).to.equal(1);
|
|
});
|
|
});
|
|
|
|
it('Sign text with openpgp.sign and verify with openpgp.verify leads to same string cleartext and valid signatures -- escape armored message', async function() {
|
|
const plaintext = pub_key_arm2;
|
|
const pubKey = await openpgp.readKey({ armoredKey: pub_key_arm2 });
|
|
const privKey = await openpgp.decryptKey({
|
|
privateKey: await openpgp.readKey({ armoredKey: priv_key_arm2 }),
|
|
passphrase: 'hello world'
|
|
});
|
|
|
|
const config = { minRSABits: 1024 };
|
|
return openpgp.sign({ signingKeys: privKey, message: await openpgp.createCleartextMessage({ text: plaintext }), config }).then(async signed => {
|
|
|
|
const message = await openpgp.readCleartextMessage({ cleartextMessage: signed });
|
|
return openpgp.verify({ verificationKeys: pubKey, message, config });
|
|
|
|
}).then(async function({ data, signatures }) {
|
|
expect(data).to.equal(plaintext);
|
|
expect(signatures).to.have.length(1);
|
|
expect(await signatures[0].verified).to.be.true;
|
|
expect((await signatures[0].signature).packets.length).to.equal(1);
|
|
});
|
|
});
|
|
|
|
it('Sign text with openpgp.sign and verify with openpgp.verify leads to same string cleartext and valid signatures -- trailing spaces', async function() {
|
|
const plaintext = 'space: \nspace and tab: \t\nno trailing space\n \ntab:\t\ntab and space:\t ';
|
|
const pubKey = await openpgp.readKey({ armoredKey: pub_key_arm2 });
|
|
const privKey = await openpgp.decryptKey({
|
|
privateKey: await openpgp.readKey({ armoredKey: priv_key_arm2 }),
|
|
passphrase: 'hello world'
|
|
});
|
|
|
|
const config = { minRSABits: 1024 };
|
|
return openpgp.sign({ signingKeys: privKey, message: await openpgp.createCleartextMessage({ text: plaintext }), config }).then(async signed => {
|
|
|
|
const message = await openpgp.readCleartextMessage({ cleartextMessage: signed });
|
|
return openpgp.verify({ verificationKeys: pubKey, message, config });
|
|
|
|
}).then(async function({ data, signatures }) {
|
|
expect(data).to.equal(plaintext.replace(/[ \t]+$/mg, ''));
|
|
expect(signatures).to.have.length(1);
|
|
expect(await signatures[0].verified).to.be.true;
|
|
expect((await signatures[0].signature).packets.length).to.equal(1);
|
|
});
|
|
});
|
|
|
|
it('Sign text with openpgp.sign and verify with openpgp.verify leads to same bytes cleartext and valid signatures - armored', async function() {
|
|
const plaintext = util.stringToUint8Array('short message\nnext line \n한국어/조선말');
|
|
const pubKey = await openpgp.readKey({ armoredKey: pub_key_arm2 });
|
|
const privKey = await openpgp.decryptKey({
|
|
privateKey: await openpgp.readKey({ armoredKey: priv_key_arm2 }),
|
|
passphrase: 'hello world'
|
|
});
|
|
|
|
const config = { minRSABits: 1024 };
|
|
return openpgp.sign({ signingKeys: privKey, message: await openpgp.createMessage({ binary: plaintext }), config }).then(async signed => {
|
|
|
|
const message = await openpgp.readMessage({ armoredMessage: signed });
|
|
return openpgp.verify({ verificationKeys: pubKey, message, format: 'binary', config });
|
|
|
|
}).then(async function({ data, signatures }) {
|
|
expect(data).to.deep.equal(plaintext);
|
|
expect(signatures).to.have.length(1);
|
|
expect(await signatures[0].verified).to.be.true;
|
|
expect((await signatures[0].signature).packets.length).to.equal(1);
|
|
});
|
|
});
|
|
|
|
it('Sign text with openpgp.sign and verify with openpgp.verify leads to same bytes cleartext and valid signatures - not armored', async function() {
|
|
const plaintext = util.stringToUint8Array('short message\nnext line \n한국어/조선말');
|
|
const pubKey = await openpgp.readKey({ armoredKey: pub_key_arm2 });
|
|
const privKey = await openpgp.decryptKey({
|
|
privateKey: await openpgp.readKey({ armoredKey: priv_key_arm2 }),
|
|
passphrase: 'hello world'
|
|
});
|
|
|
|
const config = { minRSABits: 1024 };
|
|
return openpgp.sign({ signingKeys: privKey, message: await openpgp.createMessage({ binary: plaintext }), format: 'binary', config }).then(async signed => {
|
|
|
|
const message = await openpgp.readMessage({ binaryMessage: signed });
|
|
return openpgp.verify({ verificationKeys: pubKey, message, format: 'binary', config });
|
|
|
|
}).then(async function({ data, signatures }) {
|
|
expect(data).to.deep.equal(plaintext);
|
|
expect(signatures).to.have.length(1);
|
|
expect(await signatures[0].verified).to.be.true;
|
|
expect((await signatures[0].signature).packets.length).to.equal(1);
|
|
});
|
|
});
|
|
|
|
it('Should verify detached signature with some unknown versions of Signature packets', async function () {
|
|
// Test from openpgp-interoperability-test-suite to ensure forward compatibility: https://tests.sequoia-pgp.org/?q=forward-compat
|
|
const plaintext = 'hello world';
|
|
|
|
// This signature includes two Signature packets: a v4 one (verifiable) and a 'dummy' v23 one.
|
|
const signatureUnknownTrailingPacketVersion = `-----BEGIN PGP SIGNATURE-----
|
|
|
|
wnUEARYKACcFgmSVpTQJkHEwNzxPuQajFiEE2KiARjeh+fU3dy+5cTA3PE+5
|
|
BqMAAKZNAP0fhECUqrE2Ts7Ho8/fuLFT+9jsGIGo0EviIEmW77vyhQEAtOBa
|
|
N77tTSawgDqnjIRH5RyI6YNC1LNz01VHCYWwegfCwTsXAAEKAG8FgmSVZN4J
|
|
EPv8yCoBXnMwRxQAAAAAAB4AIHNhbHRAbm90YXRpb25zLnNlcXVvaWEtcGdw
|
|
Lm9yZ8jF+epDaQ8yqg9h1mb0LcDLKC71kHyESC8fqFt9fNFsFiEE0aZuGiOx
|
|
gsmYD3iM+/zIKgFeczAAADLxDACKH0qwrZW+Eu3McHHfKojqlHoJ+Ofqotui
|
|
Gtcyx3HrE86xQHQl6346Joweomlzo2A6cjhT/nxL88sfy9yTQyUyKaON0wHz
|
|
4WI+Onu8rSaG99J/u34dDIPqFu5DzhwCrkv0IQwGYfDxG6Lrxg7gsxui2KAt
|
|
4rJqlbaeRGOTeNmew6aH74foUp86LWjdasanZ3RXxjk3yP+R/7nquQjkVGqE
|
|
jElkMwFh44TwTHlrXfI90Ki4gNrFQfbQCQm2v66rT0t3BSgVrL+FZIyXjjOh
|
|
dp83PCrkcvOcbBalvtbYPd5+23cGAylm5hkC9bxQUwUJrcJezdwSpxF5+Vgj
|
|
IkeanKfU2BhKry3Hpn3PL6vLfVkK/w0wUEbDMkFRbGAmW1sPCJWDSX6Zy75/
|
|
Li0CQ3u6tg3/m9VHUdwN5iNVk3g7AtV2eLinv4fKIuVUxUIyvacro+RBxGNc
|
|
EnZwTO2p2I0xifnoRizITFXclUc9J4vK+whpi9PHH5uoqRGcoer72rtjIIs=
|
|
=nReB
|
|
-----END PGP SIGNATURE-----`;
|
|
|
|
const publicKey = `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
|
|
|
xjMEZJWk4RYJKwYBBAHaRw8BAQdA7p5RuL+Z05qld6xRz6tbJ+9pmDowaCYr
|
|
tMOW8MXHAx3NFW5hbWUgPGVtYWlsQHRlc3QuY29tPsKMBBAWCgA+BYJklaTh
|
|
BAsJBwgJkHEwNzxPuQajAxUICgQWAAIBAhkBApsDAh4BFiEE2KiARjeh+fU3
|
|
dy+5cTA3PE+5BqMAAB5pAQDUHdYs3HRK6yJZ6IrK8lfmLzeqSgW2j9wLG/zF
|
|
TXIARQEAj0PdOzSy3q75VIQraDSHWpBAue8QNEKV4Q8hlkJvmgPOOARklaTh
|
|
EgorBgEEAZdVAQUBAQdAR9bBkzKzh24TB6gJVHR49BWnhTmeF5+vA3PXtX/b
|
|
RHkDAQgHwngEGBYIACoFgmSVpOEJkHEwNzxPuQajApsMFiEE2KiARjeh+fU3
|
|
dy+5cTA3PE+5BqMAAFjVAQDKqKwFLKX+N7le3cDLHAYSqc4AWpksKS4eSBLa
|
|
uDvEBgD+LCEUOPejUTCMqPyd04ssdOq1AlMJOmUGUwLk7kFP7Aw=
|
|
=Q9Px
|
|
-----END PGP PUBLIC KEY BLOCK-----`;
|
|
|
|
const { signatures, data } = await openpgp.verify({
|
|
message: await openpgp.createMessage({ text: plaintext }),
|
|
signature: await openpgp.readSignature({ armoredSignature: signatureUnknownTrailingPacketVersion }),
|
|
verificationKeys: await openpgp.readKey({ armoredKey: publicKey })
|
|
});
|
|
expect(data).to.equal(plaintext);
|
|
expect(signatures).to.have.length(1);
|
|
expect(await signatures[0].verified).to.be.true;
|
|
expect((await signatures[0].signature).packets.length).to.equal(1);
|
|
});
|
|
|
|
it('Should verify cleartext signature with some unknown versions of Signature packets', async function () {
|
|
// Test to ensure forward compatibility:
|
|
// this signature includes two Signature packets: a v4 one (verifiable) and a 'dummy' v23 one.
|
|
const signatureUnknownTrailingPacketVersion = `-----BEGIN PGP SIGNED MESSAGE-----
|
|
Hash: SHA512
|
|
|
|
hello world
|
|
-----BEGIN PGP SIGNATURE-----
|
|
|
|
wnUEARYKACcFgmSVpTQJkHEwNzxPuQajFiEE2KiARjeh+fU3dy+5cTA3PE+5
|
|
BqMAAKZNAP0fhECUqrE2Ts7Ho8/fuLFT+9jsGIGo0EviIEmW77vyhQEAtOBa
|
|
N77tTSawgDqnjIRH5RyI6YNC1LNz01VHCYWwegfCwTsXAAEKAG8FgmSVZN4J
|
|
EPv8yCoBXnMwRxQAAAAAAB4AIHNhbHRAbm90YXRpb25zLnNlcXVvaWEtcGdw
|
|
Lm9yZ8jF+epDaQ8yqg9h1mb0LcDLKC71kHyESC8fqFt9fNFsFiEE0aZuGiOx
|
|
gsmYD3iM+/zIKgFeczAAADLxDACKH0qwrZW+Eu3McHHfKojqlHoJ+Ofqotui
|
|
Gtcyx3HrE86xQHQl6346Joweomlzo2A6cjhT/nxL88sfy9yTQyUyKaON0wHz
|
|
4WI+Onu8rSaG99J/u34dDIPqFu5DzhwCrkv0IQwGYfDxG6Lrxg7gsxui2KAt
|
|
4rJqlbaeRGOTeNmew6aH74foUp86LWjdasanZ3RXxjk3yP+R/7nquQjkVGqE
|
|
jElkMwFh44TwTHlrXfI90Ki4gNrFQfbQCQm2v66rT0t3BSgVrL+FZIyXjjOh
|
|
dp83PCrkcvOcbBalvtbYPd5+23cGAylm5hkC9bxQUwUJrcJezdwSpxF5+Vgj
|
|
IkeanKfU2BhKry3Hpn3PL6vLfVkK/w0wUEbDMkFRbGAmW1sPCJWDSX6Zy75/
|
|
Li0CQ3u6tg3/m9VHUdwN5iNVk3g7AtV2eLinv4fKIuVUxUIyvacro+RBxGNc
|
|
EnZwTO2p2I0xifnoRizITFXclUc9J4vK+whpi9PHH5uoqRGcoer72rtjIIs=
|
|
=nReB
|
|
-----END PGP SIGNATURE-----`;
|
|
|
|
const publicKey = `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
|
|
|
xjMEZJWk4RYJKwYBBAHaRw8BAQdA7p5RuL+Z05qld6xRz6tbJ+9pmDowaCYr
|
|
tMOW8MXHAx3NFW5hbWUgPGVtYWlsQHRlc3QuY29tPsKMBBAWCgA+BYJklaTh
|
|
BAsJBwgJkHEwNzxPuQajAxUICgQWAAIBAhkBApsDAh4BFiEE2KiARjeh+fU3
|
|
dy+5cTA3PE+5BqMAAB5pAQDUHdYs3HRK6yJZ6IrK8lfmLzeqSgW2j9wLG/zF
|
|
TXIARQEAj0PdOzSy3q75VIQraDSHWpBAue8QNEKV4Q8hlkJvmgPOOARklaTh
|
|
EgorBgEEAZdVAQUBAQdAR9bBkzKzh24TB6gJVHR49BWnhTmeF5+vA3PXtX/b
|
|
RHkDAQgHwngEGBYIACoFgmSVpOEJkHEwNzxPuQajApsMFiEE2KiARjeh+fU3
|
|
dy+5cTA3PE+5BqMAAFjVAQDKqKwFLKX+N7le3cDLHAYSqc4AWpksKS4eSBLa
|
|
uDvEBgD+LCEUOPejUTCMqPyd04ssdOq1AlMJOmUGUwLk7kFP7Aw=
|
|
=Q9Px
|
|
-----END PGP PUBLIC KEY BLOCK-----`;
|
|
|
|
const { signatures } = await openpgp.verify({
|
|
message: await openpgp.readCleartextMessage({ cleartextMessage: signatureUnknownTrailingPacketVersion }),
|
|
verificationKeys: await openpgp.readKey({ armoredKey: publicKey })
|
|
});
|
|
expect(signatures).to.have.length(1);
|
|
expect(await signatures[0].verified).to.be.true;
|
|
expect((await signatures[0].signature).packets.length).to.equal(1);
|
|
});
|
|
|
|
it('Should verify cleartext message correctly when using a detached cleartext signature and binary literal data', async function () {
|
|
const plaintext = 'short message\nnext line \n한국어/조선말';
|
|
const pubKey = await openpgp.readKey({ armoredKey: pub_key_arm2 });
|
|
const privKey = await openpgp.decryptKey({
|
|
privateKey: await openpgp.readKey({ armoredKey: priv_key_arm2 }),
|
|
passphrase: 'hello world'
|
|
});
|
|
|
|
const config = { minRSABits: 1024 };
|
|
return openpgp.sign({ signingKeys: privKey, message: await openpgp.createMessage({ text: plaintext }), detached: true, config }).then(async armoredSignature => {
|
|
const signature = await openpgp.readSignature({ armoredSignature });
|
|
return openpgp.verify({ verificationKeys: pubKey, message: await openpgp.createMessage({ binary: util.encodeUTF8(plaintext) }), signature, config });
|
|
}).then(async function({ data, signatures }) {
|
|
expect(data).to.equal(plaintext);
|
|
expect(signatures).to.have.length(1);
|
|
expect(await signatures[0].verified).to.be.true;
|
|
expect((await signatures[0].signature).packets.length).to.equal(1);
|
|
});
|
|
});
|
|
|
|
it('Should verify cleartext message correctly when using a detached binary signature and text literal data', async function () {
|
|
const plaintext = 'short message\nnext line \n한국어/조선말';
|
|
const binaryPlaintext = util.encodeUTF8(plaintext);
|
|
const pubKey = await openpgp.readKey({ armoredKey: pub_key_arm2 });
|
|
const privKey = await openpgp.decryptKey({
|
|
privateKey: await openpgp.readKey({ armoredKey: priv_key_arm2 }),
|
|
passphrase: 'hello world'
|
|
});
|
|
|
|
const config = { minRSABits: 1024 };
|
|
return openpgp.sign({ signingKeys: privKey, message:await openpgp.createMessage({ binary: binaryPlaintext }), detached: true, config }).then(async armoredSignature => {
|
|
const signature = await openpgp.readSignature({ armoredSignature });
|
|
return openpgp.verify({ verificationKeys: pubKey, message: await openpgp.createMessage({ text: plaintext }), signature, config });
|
|
|
|
}).then(async function({ data, signatures }) {
|
|
expect(data).to.equal(plaintext);
|
|
expect(signatures).to.have.length(1);
|
|
expect(await signatures[0].verified).to.be.true;
|
|
expect((await signatures[0].signature).packets.length).to.equal(1);
|
|
});
|
|
});
|
|
|
|
it('Should verify encrypted cleartext message correctly when encrypting binary literal data with a canonical text signature', async function () {
|
|
const plaintext = 'short message\nnext line \n한국어/조선말';
|
|
const pubKey = await openpgp.readKey({ armoredKey: pub_key_arm2 });
|
|
const privKey = await openpgp.decryptKey({
|
|
privateKey: await openpgp.readKey({ armoredKey: priv_key_arm2 }),
|
|
passphrase: 'hello world'
|
|
});
|
|
|
|
const config = { minRSABits: 1024 };
|
|
return openpgp.sign({ signingKeys: privKey, message: await openpgp.createMessage({ text: plaintext }), detached: true, config }).then(async armoredSignature => {
|
|
const signature = await openpgp.readSignature({ armoredSignature });
|
|
return openpgp.encrypt({ message: await openpgp.createMessage({ binary: util.encodeUTF8(plaintext) }), encryptionKeys: [pubKey], signature, config });
|
|
|
|
}).then(async armoredMessage => {
|
|
const message = await openpgp.readMessage({ armoredMessage });
|
|
return openpgp.decrypt({ message, decryptionKeys: [privKey], verificationKeys: [pubKey], config });
|
|
|
|
}).then(async function({ data, signatures }) {
|
|
expect(data).to.equal(plaintext);
|
|
expect(signatures).to.have.length(1);
|
|
expect(await signatures[0].verified).to.be.true;
|
|
expect((await signatures[0].signature).packets.length).to.equal(1);
|
|
});
|
|
});
|
|
|
|
// TODO add test with multiple revocation signatures
|
|
it('Verify primary key revocation signatures', async function() {
|
|
const pubKey = await openpgp.readKey({ armoredKey: pub_revoked });
|
|
await pubKey.revocationSignatures[0].verify(
|
|
pubKey.keyPacket, openpgp.enums.signature.keyRevocation, { key: pubKey.keyPacket }
|
|
);
|
|
});
|
|
|
|
// TODO add test with multiple revocation signatures
|
|
it('Verify subkey revocation signatures', async function() {
|
|
const pubKey = await openpgp.readKey({ armoredKey: pub_revoked });
|
|
const revSig = pubKey.subkeys[0].revocationSignatures[0];
|
|
await revSig.verify(
|
|
pubKey.keyPacket, openpgp.enums.signature.subkeyRevocation, { key: pubKey.keyPacket, bind: pubKey.subkeys[0].keyPacket }
|
|
);
|
|
});
|
|
|
|
it('Verify key expiration date', async function() {
|
|
const pubKey = await openpgp.readKey({ armoredKey: pub_revoked });
|
|
|
|
expect(pubKey).to.exist;
|
|
expect(pubKey.users[0].selfCertifications[0].keyNeverExpires).to.be.false;
|
|
expect(pubKey.users[0].selfCertifications[0].keyExpirationTime).to.equal(5 * 365 * 24 * 60 * 60);
|
|
});
|
|
|
|
it('Write unhashed subpackets', async function() {
|
|
let pubKey = await openpgp.readKey({ armoredKey: pub_key_arm2 });
|
|
expect(pubKey.users[0].selfCertifications).to.exist;
|
|
pubKey = await openpgp.readKey({ armoredKey: pubKey.armor() });
|
|
expect(pubKey.users[0].selfCertifications).to.exist;
|
|
});
|
|
|
|
it('Write V4 signatures', async function() {
|
|
const pubKey = await openpgp.readKey({ armoredKey: pub_key_arm2 });
|
|
const pubKey2 = await openpgp.readKey({ armoredKey: pubKey.armor() });
|
|
expect(pubKey2).to.exist;
|
|
expect(pubKey.users[0].selfCertifications).to.eql(pubKey2.users[0].selfCertifications);
|
|
});
|
|
|
|
it('Verify a detached signature using appendSignature', async function() {
|
|
const detachedSig = ['-----BEGIN PGP SIGNATURE-----',
|
|
'Version: GnuPG v1.4.13 (Darwin)',
|
|
'Comment: GPGTools - https://gpgtools.org',
|
|
'Comment: Using GnuPG with Thunderbird - https://www.enigmail.net/',
|
|
'',
|
|
'iQEcBAEBCgAGBQJTqH5OAAoJENf7k/zfv8I8oFoH/R6EFTw2CYUQoOKSAQstWIHp',
|
|
'fVVseLOkFbByUV5eLuGVBNI3DM4GQ6C7dGntKAn34a1iTGcAIZH+fIhaZ2WtNdtA',
|
|
'R+Ijn8xDjbF/BWvcTBOaRvgw9b8viPxhkVYa3PioHYz6krt/LmFqFdp/phWZcqR4',
|
|
'jzWMX55h4FOw3YBNGiz2NuIg+iGrFRWPYgd8NVUmJKReZHs8C/6HGz7F4/A24k6Y',
|
|
'7xms9D6Er+MhspSl+1dlRdHjtXiRqC5Ld1hi2KBKc6YzgOLpVw5l9sffbnH+aRG4',
|
|
'dH+2J5U3elqBDK1i3GyG8ixLSB0FGW9+lhYNosZne2xy8SbQKdgsnTBnWSGevP0=',
|
|
'=xiih',
|
|
'-----END PGP SIGNATURE-----'].join('\r\n');
|
|
|
|
const content = ['Content-Type: multipart/mixed;',
|
|
' boundary="------------070307080002050009010403"',
|
|
'',
|
|
'This is a multi-part message in MIME format.',
|
|
'--------------070307080002050009010403',
|
|
'Content-Type: text/plain; charset=ISO-8859-1',
|
|
'Content-Transfer-Encoding: quoted-printable',
|
|
'',
|
|
'test11',
|
|
'',
|
|
'--------------070307080002050009010403',
|
|
'Content-Type: application/macbinary;',
|
|
' name="test.bin"',
|
|
'Content-Transfer-Encoding: base64',
|
|
'Content-Disposition: attachment;',
|
|
' filename="test.bin"',
|
|
'',
|
|
'dGVzdGF0dGFjaG1lbnQ=',
|
|
'--------------070307080002050009010403--',
|
|
''].join('\r\n');
|
|
|
|
const publicKeyArmored = '-----BEGIN PGP PUBLIC KEY BLOCK-----\r\nVersion: OpenPGP.js v.1.20131116\r\nComment: Whiteout Mail - https://whiteout.io\r\n\r\nxsBNBFKODs4BB/9iOF4THsjQMY+WEpT7ShgKxj4bHzRRaQkqczS4nZvP0U3g\r\nqeqCnbpagyeKXA+bhWFQW4GmXtgAoeD5PXs6AZYrw3tWNxLKu2Oe6Tp9K/XI\r\nxTMQ2wl4qZKDXHvuPsJ7cmgaWqpPyXtxA4zHHS3WrkI/6VzHAcI/y6x4szSB\r\nKgSuhI3hjh3s7TybUC1U6AfoQGx/S7e3WwlCOrK8GTClirN/2mCPRC5wuIft\r\nnkoMfA6jK8d2OPrJ63shy5cgwHOjQg/xuk46dNS7tkvGmbaa+X0PgqSKB+Hf\r\nYPPNS/ylg911DH9qa8BqYU2QpNh9jUKXSF+HbaOM+plWkCSAL7czV+R3ABEB\r\nAAHNLVdoaXRlb3V0IFVzZXIgPHNhZmV3aXRobWUudGVzdHVzZXJAZ21haWwu\r\nY29tPsLAXAQQAQgAEAUCUo4O2gkQ1/uT/N+/wjwAAN2cB/9gFRmAfvEQ2qz+\r\nWubmT2EsSSnjPMxzG4uyykFoa+TaZCWo2Xa2tQghmU103kEkQb1OEjRjpgwJ\r\nYX9Kghnl8DByM686L5AXnRyHP78qRJCLXSXl0AGicboUDp5sovaa4rswQceH\r\nvcdWgZ/mgHTRoiQeJddy9k+H6MPFiyFaVcFwegVsmpc+dCcC8yT+qh8ZIbyG\r\nRJU60PmKKN7LUusP+8DbSv39zCGJCBlVVKyA4MzdF5uM+sqTdXbKzOrT5DGd\r\nCZaox4s+w16Sq1rHzZKFWfQPfKLDB9pyA0ufCVRA3AF6BUi7G3ZqhZiHNhMP\r\nNvE45V/hS1PbZcfPVoUjE2qc1Ix1\r\n=7Wpe\r\n-----END PGP PUBLIC KEY BLOCK-----';
|
|
const publicKey = await openpgp.readKey({ armoredKey: publicKeyArmored });
|
|
|
|
const message = await openpgp.createMessage({ text: content });
|
|
await message.appendSignature(detachedSig);
|
|
const { data, signatures } = await openpgp.verify({ verificationKeys:[publicKey], message, config: { minRSABits: 1024, allowMissingKeyFlags: true } });
|
|
expect(data).to.equal(content);
|
|
expect(signatures).to.have.length(1);
|
|
expect(await signatures[0].verified).to.be.true;
|
|
expect((await signatures[0].signature).packets.length).to.equal(1);
|
|
expect(await signatures[0].verified).to.be.true;
|
|
});
|
|
|
|
it('Detached signature signing and verification', async function() {
|
|
const message = await openpgp.createMessage({ text: 'hello' });
|
|
const pubKey = await openpgp.readKey({ armoredKey: pub_key_arm2 });
|
|
const privKey = await openpgp.decryptKey({
|
|
privateKey: await openpgp.readKey({ armoredKey: priv_key_arm2 }),
|
|
passphrase: 'hello world'
|
|
});
|
|
|
|
const opt = { userIDs: { name:'test', email:'a@b.com' }, format: 'object' };
|
|
const { privateKey: generatedKey } = await openpgp.generateKey(opt);
|
|
const armoredSignature = await openpgp.sign({ signingKeys: [generatedKey, privKey], message, detached: true, config: { minRSABits: 1024 } });
|
|
const signature = await openpgp.readSignature({ armoredSignature });
|
|
const { data, signatures } = await openpgp.verify({ verificationKeys: [generatedKey.toPublic(), pubKey], message, signature, config: { minRSABits: 1024 } });
|
|
expect(data).to.equal('hello');
|
|
expect(await signatures[0].verified).to.be.true;
|
|
expect(await signatures[1].verified).to.be.true;
|
|
});
|
|
|
|
it('Sign message with key without password', function() {
|
|
const opt = { userIDs: { name:'test', email:'a@b.com' }, passphrase: null, format: 'object' };
|
|
return openpgp.generateKey(opt).then(async function({ privateKey: key }) {
|
|
const message = await openpgp.createMessage({ text: 'hello world' });
|
|
return message.sign([key]);
|
|
});
|
|
});
|
|
|
|
it('Verify signed key', async function() {
|
|
const signedArmor = [
|
|
'-----BEGIN PGP PUBLIC KEY BLOCK-----',
|
|
'Version: GnuPG v1',
|
|
'',
|
|
'mI0EUmEvTgEEANyWtQQMOybQ9JltDqmaX0WnNPJeLILIM36sw6zL0nfTQ5zXSS3+',
|
|
'fIF6P29lJFxpblWk02PSID5zX/DYU9/zjM2xPO8Oa4xo0cVTOTLj++Ri5mtr//f5',
|
|
'GLsIXxFrBJhD/ghFsL3Op0GXOeLJ9A5bsOn8th7x6JucNKuaRB6bQbSPABEBAAG0',
|
|
'JFRlc3QgTWNUZXN0aW5ndG9uIDx0ZXN0QGV4YW1wbGUuY29tPoi5BBMBAgAjBQJS',
|
|
'YS9OAhsvBwsJCAcDAgEGFQgCCQoLBBYCAwECHgECF4AACgkQSmNhOk1uQJQwDAP6',
|
|
'AgrTyqkRlJVqz2pb46TfbDM2TDF7o9CBnBzIGoxBhlRwpqALz7z2kxBDmwpQa+ki',
|
|
'Bq3jZN/UosY9y8bhwMAlnrDY9jP1gdCo+H0sD48CdXybblNwaYpwqC8VSpDdTndf',
|
|
'9j2wE/weihGp/DAdy/2kyBCaiOY1sjhUfJ1GogF49rCIRgQQEQIABgUCVuXBfQAK',
|
|
'CRARJ5QDyxae+O0fAJ9hUQPejXvZv6VW1Q3/Pm3+x2wfJACgwFg9NlrPPfejoC1w',
|
|
'P+z+vE5NFA24jQRSYS9OAQQA6R/PtBFaJaT4jq10yqASk4sqwVMsc6HcifM5lSdx',
|
|
'zExFP74naUMMyEsKHP53QxTF0GrqusagQg/ZtgT0CN1HUM152y7ACOdp1giKjpMz',
|
|
'OTQClqCoclyvWOFB+L/SwGEIJf7LSCErwoBuJifJc8xAVr0XX0JthoW+uP91eTQ3',
|
|
'XpsAEQEAAYkBPQQYAQIACQUCUmEvTgIbLgCoCRBKY2E6TW5AlJ0gBBkBAgAGBQJS',
|
|
'YS9OAAoJEOCE90RsICyXuqIEANmmiRCASF7YK7PvFkieJNwzeK0V3F2lGX+uu6Y3',
|
|
'Q/Zxdtwc4xR+me/CSBmsURyXTO29OWhPGLszPH9zSJU9BdDi6v0yNprmFPX/1Ng0',
|
|
'Abn/sCkwetvjxC1YIvTLFwtUL/7v6NS2bZpsUxRTg9+cSrMWWSNjiY9qUKajm1tu',
|
|
'zPDZXAUEAMNmAN3xXN/Kjyvj2OK2ck0XW748sl/tc3qiKPMJ+0AkMF7Pjhmh9nxq',
|
|
'E9+QCEl7qinFqqBLjuzgUhBU4QlwX1GDAtNTq6ihLMD5v1d82ZC7tNatdlDMGWnI',
|
|
'dvEMCv2GZcuIqDQ9rXWs49e7tq1NncLYhz3tYjKhoFTKEIq3y3Pp',
|
|
'=fvK7',
|
|
'-----END PGP PUBLIC KEY BLOCK-----'
|
|
].join('\n');
|
|
|
|
const signedKey = await openpgp.readKey({ armoredKey: signedArmor });
|
|
const signerKey = await openpgp.readKey({ armoredKey: priv_key_arm1 });
|
|
return signedKey.verifyPrimaryUser([signerKey], undefined, undefined, { ...openpgp.config, rejectPublicKeyAlgorithms: new Set() }).then(signatures => {
|
|
expect(signatures[0].valid).to.be.null;
|
|
expect(signatures[0].keyID.toHex()).to.equal(signedKey.getKeyID().toHex());
|
|
expect(signatures[1].valid).to.be.true;
|
|
expect(signatures[1].keyID.toHex()).to.equal(signerKey.getKeyID().toHex());
|
|
});
|
|
});
|
|
|
|
it('Verify signed UserIDs and User Attributes', async function() {
|
|
const armoredKeyWithPhoto = `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
|
|
|
mI0EW1CJGAEEAM+BzuFzcYk9HttmDbjGexQ8dfme074Q5PuHas3PBISPm0AwmnDM
|
|
tzjlcrrg2VGuLqHvNF600w2ZgOo2gElNYCOas1q/fVFuIgJ4SUduNOEe/JnIW4uP
|
|
iEGU9l6zOVVgTc/nGVpZdvHgvOL8nl9BKHtWEnMD3Du7UYAm+Avshu9jABEBAAG0
|
|
AViI1AQTAQoAPhYhBKcH118Rrg0wLBrTk5IyMikCym+4BQJbUIkYAhsDBQkDwmcA
|
|
BQsJCAcDBRUKCQgLBRYDAgEAAh4BAheAAAoJEJIyMikCym+4K8oEAJc7YFiNau6V
|
|
HTVK4cTvWU5MuYiejejFZai4ELUJy+WF6cZYrLuF/z/kRt8B7hpumXChPCUlT0q7
|
|
FWypQtA3leu83DGMXqhfS80h2S1+VLmDVVWKQXOwgOb44jT9F08bDU5QK08SkjF8
|
|
/EirIy8ANzdwCA4rHytIS2yx6tLlthvX0cBwwG4BEAABAQAAAAAAAAAAAAAAAP/Y
|
|
/+AAEEpGSUYAAQEAAAEAAQAA/9sAQwABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB
|
|
AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB/9sAQwEBAQEB
|
|
AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB
|
|
AQEBAQEBAQEBAQEB/8AAEQgAAQABAwEiAAIRAQMRAf/EABUAAQEAAAAAAAAAAAAA
|
|
AAAAAAAK/8QAFBABAAAAAAAAAAAAAAAAAAAAAP/EABQBAQAAAAAAAAAAAAAAAAAA
|
|
AAD/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwC/gAH/2YjUBBMB
|
|
CgA+FiEEpwfXXxGuDTAsGtOTkjIyKQLKb7gFAltQimUCGwMFCQPCZwAFCwkIBwMF
|
|
FQoJCAsFFgMCAQACHgECF4AACgkQkjIyKQLKb7gm/wQAiyZF89qr8hf3XQNJ6Ir/
|
|
QtaniPcesjrYCIE47ZfeDYpBTPeiMm295o2dZXVJS4ItllYsplASw5DJiIMnQKlJ
|
|
mbXakYFzzclTa/JrKzFYCy/DPT95xK+633omgrIUgJodizoKJE7XeB2U6aRUJJ4O
|
|
iTuGu4fEU1UligAXSrZmCdE=
|
|
=VK6I
|
|
-----END PGP PUBLIC KEY BLOCK-----`;
|
|
|
|
const key = await openpgp.readKey({ armoredKey: armoredKeyWithPhoto });
|
|
await Promise.all(key.users.map(async user => {
|
|
await user.verify(undefined, openpgp.config);
|
|
}));
|
|
});
|
|
|
|
it('should verify a shorter RSA signature', async function () {
|
|
const encrypted = `-----BEGIN PGP MESSAGE-----
|
|
|
|
wYwD4IT3RGwgLJcBBACmH+a2c2yieZJ3wFchKeTVqzWkoltiidWgHHNE5v5x
|
|
8aZGNzZFBd02v80VS23P9oxeJOpqKX2IZyuD36SniNoi+eXdT3zraqIe9x5p
|
|
0RY9OrTP9pl58iogFBi1ARls41j7ui8KKDt2/iyQDCWHW1LoOVstiEb5/Xi3
|
|
EWI+34EbNNTBMgEJAQAwEXImkOPmhYhE7bB3FnXe9rb7Fo3GZYA4/8B9YVf7
|
|
GGZRLGwbICGu8E0MolmzLYW9hRThEfusAsNPGSgB+Yaqp0drsk01N4JJj3FT
|
|
RKEUvd5EcL3u+Z5EoUUW6GpUL5p8Hvy2thqQfeem7XUbDBY6V3wqydOjbN9u
|
|
c4CWB5Zu3GjDGDOvXFsy6cgdQvd/B9xbugKvUbAIsecTPlLtjZwfQklIu63T
|
|
DA/3Pz/+zTAknBCsuIM0m7U/ZP3N6AGQIp4To7RJk0I6AxthHF5LbU11MjDZ
|
|
iB7+vmhqlrPyIS11g25UNijottJm13f84glVwBdWTJCiEqjh3KbcnTQCckCY
|
|
V39DDLtbZG/XIx1ktqp765O9D/9xp2IA4zTyZzH4TuDbYs1j+JRdMsAq254k
|
|
1m+wtW5gxJGcD5nh2T2T+ABL0n3jW0G504kR0LNBAQOZhVSKnSLn+F0GkjmI
|
|
iGw8+BOy8p2pX/WCLOf776ppSL77TpzhpG6wSE2oQxDrudazmRgVkZpyGzFE
|
|
fDjspLTJHOhZ5zlLuoiKS9qEARGp39ysQnElR4dsx7tyVZz0uJvIrVzrQBlB
|
|
ekoD0DH0bhfqiwDrqeTJT2ORk8I/Q3jWnhQ3MnRN+q9d0yf1LWApMCwA7xU2
|
|
C4KUFRC/wuF2TR9NvA==
|
|
=v3WS
|
|
-----END PGP MESSAGE-----`;
|
|
const armoredKey = `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
|
|
|
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
|
|
oaBUyhCKt8tz6Q==
|
|
=52k1
|
|
-----END PGP PRIVATE KEY BLOCK-----`;
|
|
const key = await openpgp.readKey({ armoredKey });
|
|
const decrypted = await openpgp.decrypt({
|
|
message: await openpgp.readMessage({ armoredMessage: encrypted, config: { enableParsingV5Entities: true } }),
|
|
verificationKeys: key,
|
|
decryptionKeys: key,
|
|
config: { minRSABits: 1024 }
|
|
});
|
|
expect(await decrypted.signatures[0].verified).to.be.true;
|
|
});
|
|
|
|
it('should verify a shorter EdDSA signature', async function() {
|
|
const key = await openpgp.readKey({
|
|
armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
|
|
|
xVgEX8+jfBYJKwYBBAHaRw8BAQdA9GbdDjprR0sWf0R5a5IpulUauc0FsmzJ
|
|
mOYCfoowt8EAAP9UwaqC0LWWQ5RlX7mps3728vFa/If1KBVwAjk7Uqhi2BKL
|
|
zQ90ZXN0MiA8YkBhLmNvbT7CjAQQFgoAHQUCX8+jfAQLCQcIAxUICgQWAgEA
|
|
AhkBAhsDAh4BACEJEG464aV2od77FiEEIcg441MtKnyJnPDRbjrhpXah3vuR
|
|
gQD+Il6Gw2oIok4/ANyDDLBYZtKqRrMv4NcfF9DHYuAFcP4BAPhFOffyP3qU
|
|
AEZb7QPrWdLfhn8/FeSFZxJvnmupQ9sDx10EX8+jfBIKKwYBBAGXVQEFAQEH
|
|
QOSzo9cX1U2esGFClprOt0QWXNJ97228R5tKFxo6/0NoAwEIBwAA/0n4sq2i
|
|
N6/jE+6rVO4o/7LW0xahxpV1tTA6qv1Op9TwFIDCeAQYFggACQUCX8+jfAIb
|
|
DAAhCRBuOuGldqHe+xYhBCHIOONTLSp8iZzw0W464aV2od773XcA/jlmX8/c
|
|
1/zIotEkyMZB4mI+GAg3FQ6bIACFBH1sz0MzAP9Snri0P4FRZ8D5THRCJoUm
|
|
GBgpBmrf6IVv484jBswGDA==
|
|
=8rBO
|
|
-----END PGP PRIVATE KEY BLOCK-----`
|
|
});
|
|
const encrypted = `-----BEGIN PGP MESSAGE-----
|
|
|
|
wV4DWlRRjuYiLSsSAQdAWwDKQLN4ZUS5fqiwFtAMrRfZZe9J4SgClhG6avEe
|
|
AEowkSZwWRT+8Hy8aBIb4oPehYUFXXZ7BtlJCyd7LOTUtqyc00OE0721PC3M
|
|
v0+zird60sACATlDmTwweR5GFtEAjHVheIL5rbkOBRD+oSqB8z+IovNg83Pz
|
|
FVwsFZnCLtECoYgpF2MJdopuC/bPHcrvf4ndwmD11uXtms4Rq4y25QyqApbn
|
|
Hj/hljufk0OkavUXxrNKjGQtxLHMpa3Nsi0MHWY8JguxOKFKpAIMP32CD1e+
|
|
j+GItrR+QbbN13ODlcR3hf66cwjLLsJCx5VcBaRspKF05O3ix/u9KVjJqtbi
|
|
Ie6jnY0zP2ldtS4JmhKBa43qmOHCxHc=
|
|
=7B58
|
|
-----END PGP MESSAGE-----`;
|
|
const decrypted = await openpgp.decrypt({ message: await openpgp.readMessage({ armoredMessage: encrypted }), decryptionKeys: key, verificationKeys: key.toPublic() });
|
|
expect(await decrypted.signatures[0].verified).to.be.true;
|
|
});
|
|
|
|
it('should verify a shorter ECDSA signature', async function() {
|
|
const key = await openpgp.readKey({
|
|
armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
|
|
|
xYAFX9JrLRMAAABMCCqGSM49AwEHAgMErtQdX4vh7ng/ut+k1mooYNh3Ywqt
|
|
wr0tSS8hxZMvQRIFQ53Weq0e97ioZKXGimprEL571yvAN7I19wtQtqi61AAA
|
|
AAAAJAEAjWdW+qlMFaKwXCls3O/X8I1rbZ0OdFgeE3TnRP3YETAP5s0KYSA8
|
|
YUBhLml0PsKSBRATCAAhBQJf0mstBAsJBwgDFQgKBBYCAQACGQECGwMCHgcD
|
|
IgECACMiIQUee6Tb+GlhTk/ozKrt7RhInCyR6w3OJb/tYAN1+qbIoYUqAP9S
|
|
XmJCmSMrq6KfAD1aWSTBhtmujh+6y/pYTaf6VJVBYQEAt18zK0tw5EihHASY
|
|
FXbfdFHBzrMmPJ4UV6UiBvH6k2zHhAVf0mstEgAAAFAIKoZIzj0DAQcCAwQx
|
|
qnVPmWex365Nx8X8BGuMNI2TITXzTh9+AuPftZjPm09dhxdT9xmrCstPu/U1
|
|
cpacIp0LIq13ngLgeZWcGFcnAwEIBwAAAAAAJAEAsTvBsKk/XoCz2mi8sz5q
|
|
EYaN9YdDOU2jF+HOaSNaJAsPF8J6BRgTCAAJBQJf0mstAhsMACMiIQUee6Tb
|
|
+GlhTk/ozKrt7RhInCyR6w3OJb/tYAN1+qbIoVutAP9GHPLn7D9Uahm81lhK
|
|
AcvDfr9a0Cp4WAVzKDKLUzrRMgEAozi0VyjiBo1U2LcwTPJkA4PEQqQRVW1D
|
|
KZTMSAH7JEo=
|
|
=tqWy
|
|
-----END PGP PRIVATE KEY BLOCK-----`,
|
|
config: { enableParsingV5Entities: true }
|
|
});
|
|
const signed = `-----BEGIN PGP SIGNED MESSAGE-----
|
|
Hash: SHA256
|
|
|
|
short message
|
|
-----BEGIN PGP SIGNATURE-----
|
|
|
|
wnYFARMIAAYFAl/Say0AIyIhBR57pNv4aWFOT+jMqu3tGEicLJHrDc4lv+1g
|
|
A3X6psihFkcA+Nuog2qpAq20Zc2lzVjDZzQosb8MLvKMg3UFCX12Oc0BAJwd
|
|
JImeZLY02MctIpGZULbqgcUGK0P/yqrPL8Pe4lQM
|
|
=Pacb
|
|
-----END PGP SIGNATURE-----`;
|
|
const message = await openpgp.readCleartextMessage({ cleartextMessage: signed, config: { enableParsingV5Entities: true } });
|
|
const verified = await openpgp.verify({ verificationKeys: key, message });
|
|
expect(await verified.signatures[0].verified).to.be.true;
|
|
});
|
|
|
|
it('Should parse a signature with a critical unknown subpacket, but not verify it', async function() {
|
|
const key = await openpgp.readKey({
|
|
armoredKey: `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
|
|
|
xjMEZmsxYRYJKwYBBAHaRw8BAQdAgPH3tbfVO4CNqRQevvYW6kYY0qpNQltw
|
|
CegLonECw/vNBFRlc3TCwBgEEBYKAIoFgmZrMWEDCwkHCZAFbxb2+9/G3UUU
|
|
AAAAAAAcACBzYWx0QG5vdGF0aW9ucy5vcGVucGdwanMub3Jn1Bg/fpBZjM6n
|
|
CMTgcCh7+NHCoTmgpPef1+7CO792jL4FFQgKDA4EFgACAQIZAQKbAwIeARYh
|
|
BL/u0Jl6QJQVEZ0grQVvFvb738bdBOMBAgMAAMAYAQD25k4by+9P5WuOvirp
|
|
MhKE441PBb1n3fhaVpLogoVgZwD/ST2+Y5G6NdJM+U45iwfZDfa3ix1/zUSf
|
|
DF+cVdXVOwrOOARmazFhEgorBgEEAZdVAQUBAQdAGVw9vpajNPafAzshTmok
|
|
O1ZCDuQN9KkV+qTxZ7JGoEIDAQgHwsADBBgWCgB1BYJmazFhCZAFbxb2+9/G
|
|
3UUUAAAAAAAcACBzYWx0QG5vdGF0aW9ucy5vcGVucGdwanMub3JnRIP2KWB1
|
|
C8+8vpmscsPPBl+KYeNcCbCOJqo7G3A5ES0CmwwWIQS/7tCZekCUFRGdIK0F
|
|
bxb2+9/G3QTjAQIDAABj9wEA2E/C98UXszf4TWH7/xBGICoDDNxceMhSDvtt
|
|
nYhoNlUA/Ar+Ofx+vMf9oYcNjPEbYu/yu1AtKY44aZvDBLK2+OAI
|
|
=YrJy
|
|
-----END PGP PUBLIC KEY BLOCK-----`
|
|
});
|
|
await expect(key.verifyPrimaryKey()).to.be.rejectedWith(/Unknown critical signature subpacket type 99/);
|
|
});
|
|
});
|