From 2bb3c30025918fe0645e1b811401f5169ced7b34 Mon Sep 17 00:00:00 2001
From: Brian Bloniarz <brian.bloniarz@gmail.com>
Date: Wed, 13 Feb 2013 22:27:40 -0800
Subject: [PATCH] openpgp_keyring include subkeys by ID

openpgp_keyring.getPublicKeysForKeyId will now search subkeys
when looking for the ID, and return a key object based on that
subkey.

Updated to add a method, getSubKeyAsKey, to openpgp_msg_publickey.
This returns a full-fledged openpgp_msg_publickey object for a
chosen subkey.
---
 resources/openpgp.js             | 31 ++++++++++++++++---
 resources/openpgp.min.js         | 11 ++++---
 src/openpgp.keyring.js           | 19 ++++++++++--
 src/openpgp.msg.publickey.js     | 10 ++++++
 test/ciphers/openpgp.sigcheck.js | 52 ++++++++++++++++++++++++++++++++
 5 files changed, 111 insertions(+), 12 deletions(-)

diff --git a/resources/openpgp.js b/resources/openpgp.js
index fec55f85..e0b7c1e4 100644
--- a/resources/openpgp.js
+++ b/resources/openpgp.js
@@ -2969,7 +2969,7 @@ function openpgp_config() {
 			keyserver: "keyserver.linux.it" // "pgp.mit.edu:11371"
 	};
 
-	this.versionstring ="OpenPGP.js v.1.20130206";
+	this.versionstring ="OpenPGP.js v.1.20130213";
 	this.commentstring ="http://openpgpjs.org";
 	/**
 	 * reads the config out of the HTML5 local storage
@@ -9233,9 +9233,22 @@ function openpgp_keyring() {
 	 */
 	function getPublicKeysForKeyId(keyId) {
 		var result = new Array();
-		for (var i=0; i < this.publicKeys.length; i++)
-			if (keyId == this.publicKeys[i].obj.getKeyId())
-				result[result.length] = this.publicKeys[i];
+		for (var i=0; i < this.publicKeys.length; i++) {
+			var key = this.publicKeys[i];
+			if (keyId == key.obj.getKeyId())
+				result[result.length] = key;
+			else if (key.obj.subKeys != null) {
+				for (var j=0; j < key.obj.subKeys.length; j++) {
+					var subkey = key.obj.subKeys[j];
+					if (keyId == subkey.getKeyId()) {
+						result[result.length] = {
+								obj: key.obj.getSubKeyAsKey(j),
+								keyId: subkey.getKeyId()
+						}
+					}
+				}
+			}
+		}
 		return result;
 	}
 	this.getPublicKeysForKeyId = getPublicKeysForKeyId;
@@ -9585,6 +9598,15 @@ function openpgp_msg_publickey() {
 		return null;
 	}
 
+        /* Returns the i-th subKey as a openpgp_msg_publickey object */
+	function getSubKeyAsKey(i) {
+		var ret = new openpgp_msg_publickey();
+		ret.userIds = this.userIds;
+		ret.userAttributes = this.userAttributes;
+		ret.publicKeyPacket = this.subKeys[i];
+		return ret;
+	}
+
 	this.getEncryptionKey = getEncryptionKey;
 	this.getSigningKey = getSigningKey;
 	this.read_nodes = read_nodes;
@@ -9594,6 +9616,7 @@ function openpgp_msg_publickey() {
 	this.getFingerprint = getFingerprint;
 	this.getKeyId = getKeyId;
 	this.verifyBasicSignatures = verifyBasicSignatures;
+	this.getSubKeyAsKey = getSubKeyAsKey;
 }
 // GPG4Browsers - An OpenPGP implementation in javascript
 // Copyright (C) 2011 Recurity Labs GmbH
diff --git a/resources/openpgp.min.js b/resources/openpgp.min.js
index e703ddd1..b66b8684 100644
--- a/resources/openpgp.min.js
+++ b/resources/openpgp.min.js
@@ -80,7 +80,7 @@ JXG.Util.asciiCharCodeAt=function(b,a){var c=b.charCodeAt(a);if(255<c)switch(c){
 151;break;case 732:c=152;break;case 8482:c=153;break;case 353:c=154;break;case 8250:c=155;break;case 339:c=156;break;case 382:c=158;break;case 376:c=159}return c};
 JXG.Util.utf8Decode=function(b){var a=[],c=0,d=0,e=0,f;if(!JXG.exists(b))return"";for(;c<b.length;)d=b.charCodeAt(c),128>d?(a.push(String.fromCharCode(d)),c++):191<d&&224>d?(e=b.charCodeAt(c+1),a.push(String.fromCharCode((d&31)<<6|e&63)),c+=2):(e=b.charCodeAt(c+1),f=b.charCodeAt(c+2),a.push(String.fromCharCode((d&15)<<12|(e&63)<<6|f&63)),c+=3);return a.join("")};
 JXG.Util.genUUID=function(){for(var b="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".split(""),a=Array(36),c=0,d,e=0;36>e;e++)8==e||13==e||18==e||23==e?a[e]="-":14==e?a[e]="4":(2>=c&&(c=33554432+16777216*Math.random()|0),d=c&15,c>>=4,a[e]=b[19==e?d&3|8:d]);return a.join("")};
-function openpgp_config(){this.config=null;this.default_config={prefer_hash_algorithm:2,encryption_cipher:9,compression:1,show_version:!0,show_comment:!0,integrity_protect:!0,composition_behavior:0,keyserver:"keyserver.linux.it"};this.versionstring="OpenPGP.js v.1.20130206";this.commentstring="http://openpgpjs.org";this.debug=!1;this.read=function(){var b=JSON.parse(window.localStorage.getItem("config"));null==b?(this.config=this.default_config,this.write()):this.config=b};this.write=function(){window.localStorage.setItem("config",
+function openpgp_config(){this.config=null;this.default_config={prefer_hash_algorithm:2,encryption_cipher:9,compression:1,show_version:!0,show_comment:!0,integrity_protect:!0,composition_behavior:0,keyserver:"keyserver.linux.it"};this.versionstring="OpenPGP.js v.1.20130213";this.commentstring="http://openpgpjs.org";this.debug=!1;this.read=function(){var b=JSON.parse(window.localStorage.getItem("config"));null==b?(this.config=this.default_config,this.write()):this.config=b};this.write=function(){window.localStorage.setItem("config",
 JSON.stringify(this.config))}}
 function openpgp_cfb_encrypt(b,a,c,d,e,f){var g=Array(d),h=Array(d),b=b+b.charAt(d-2)+b.charAt(d-1);util.print_debug("prefixrandom:"+util.hexstrdump(b));for(var j="",k=0;k<d;k++)g[k]=0;h=a(g,e);for(k=0;k<d;k++)j+=String.fromCharCode(h[k]^b.charCodeAt(k));for(k=0;k<d;k++)g[k]=j.charCodeAt(k);h=a(g,e);j+=String.fromCharCode(h[0]^b.charCodeAt(d));j+=String.fromCharCode(h[1]^b.charCodeAt(d+1));if(f)for(k=0;k<d;k++)g[k]=j.charCodeAt(k+2);else for(k=0;k<d;k++)g[k]=j.charCodeAt(k);h=a(g,e);if(f){for(k=0;k<
 d;k++)j+=String.fromCharCode(h[k]^c.charCodeAt(k));for(n=d+2;n<c.length;n+=d){for(k=0;k<d;k++)g[k]=j.charCodeAt(n+k);h=a(g,e);for(k=0;k<d;k++)j+=String.fromCharCode(h[k]^c.charCodeAt(n-2+k))}}else{c="  "+c;for(k=2;k<d;k++)j+=String.fromCharCode(h[k]^c.charCodeAt(k));b=j.substring(0,2*d).split("");j=j.substring(d);for(n=d;n<c.length;n+=d){for(k=0;k<d;k++)g[k]=j.charCodeAt(k);j="";h=a(g,e);for(k=0;k<d;k++)b.push(String.fromCharCode(h[k]^c.charCodeAt(n+k))),j+=String.fromCharCode(h[k]^c.charCodeAt(n+
@@ -350,9 +350,10 @@ publicKey:g}}
 function openpgp_keyring(){this.init=function(){var b=JSON.parse(window.localStorage.getItem("privatekeys")),a=JSON.parse(window.localStorage.getItem("publickeys"));if(null==b||0==b.length)b=[];if(null==a||0==a.length)a=[];this.publicKeys=[];this.privateKeys=[];for(var c=0,d=0;d<b.length;d++){var e=openpgp.read_privateKey(b[d]);this.privateKeys[c]={armored:b[d],obj:e[0],keyId:e[0].getKeyId()};c++}for(d=c=0;d<a.length;d++)e=openpgp.read_publicKey(a[d]),null!=e[0]&&(this.publicKeys[c]={armored:a[d],
 obj:e[0],keyId:e[0].getKeyId()},c++)};this.hasPrivateKey=function(){return 0<this.privateKeys.length};this.store=function(){for(var b=[],a=0;a<this.privateKeys.length;a++)b[a]=this.privateKeys[a].armored;for(var c=[],a=0;a<this.publicKeys.length;a++)c[a]=this.publicKeys[a].armored;window.localStorage.setItem("privatekeys",JSON.stringify(b));window.localStorage.setItem("publickeys",JSON.stringify(c))};this.getPublicKeyForAddress=function(b){var a=[],c=b.split("<"),d="",d=1<c.length?c[1].split(">")[0]:
 b.trim(),d=d.toLowerCase();if(!util.emailRegEx.test(d))return a;for(b=0;b<this.publicKeys.length;b++)for(c=0;c<this.publicKeys[b].obj.userIds.length;c++)0<=this.publicKeys[b].obj.userIds[c].text.toLowerCase().indexOf(d)&&(a[a.length]=this.publicKeys[b]);return a};this.getPrivateKeyForAddress=function(b){var a=[],c=b.split("<"),d="",d=1<c.length?c[1].split(">")[0]:b.trim(),d=d.toLowerCase();if(!util.emailRegEx.test(d))return a;for(b=0;b<this.privateKeys.length;b++)for(c=0;c<this.privateKeys[b].obj.userIds.length;c++)0<=
-this.privateKeys[b].obj.userIds[c].text.toLowerCase().indexOf(d)&&(a[a.length]=this.privateKeys[b]);return a};this.getPublicKeysForKeyId=function(b){for(var a=[],c=0;c<this.publicKeys.length;c++)b==this.publicKeys[c].obj.getKeyId()&&(a[a.length]=this.publicKeys[c]);return a};this.getPrivateKeyForKeyId=function(b){for(var a=[],c=0;c<this.privateKeys.length;c++)if(b==this.privateKeys[c].obj.getKeyId()&&(a[a.length]={key:this.privateKeys[c],keymaterial:this.privateKeys[c].obj.privateKeyPacket}),null!=
-this.privateKeys[c].obj.subKeys)for(var d=this.privateKeys[c].obj.getSubKeyIds(),e=0;e<d.length;e++)b==util.hexstrdump(d[e])&&(a[a.length]={key:this.privateKeys[c],keymaterial:this.privateKeys[c].obj.subKeys[e]});return a};this.importPublicKey=function(b){for(var a=openpgp.read_publicKey(b),c=0;c<a.length;c++)this.publicKeys[this.publicKeys.length]={armored:b,obj:a[c],keyId:a[c].getKeyId()};return!0};this.importPrivateKey=function(b,a){var c=openpgp.read_privateKey(b);if(!c[0].decryptSecretMPIs(a))return!1;
-for(var d=0;d<c.length;d++)this.privateKeys[this.privateKeys.length]={armored:b,obj:c[d],keyId:c[d].getKeyId()};return!0};this.exportPublicKey=function(b){return this.publicKey[b]};this.removePublicKey=function(b){b=this.publicKeys.splice(b,1);this.store();return b};this.exportPrivateKey=function(b){return this.privateKeys[b]};this.removePrivateKey=function(b){b=this.privateKeys.splice(b,1);this.store();return b}}
+this.privateKeys[b].obj.userIds[c].text.toLowerCase().indexOf(d)&&(a[a.length]=this.privateKeys[b]);return a};this.getPublicKeysForKeyId=function(b){for(var a=[],c=0;c<this.publicKeys.length;c++){var d=this.publicKeys[c];if(b==d.obj.getKeyId())a[a.length]=d;else if(null!=d.obj.subKeys)for(var e=0;e<d.obj.subKeys.length;e++){var f=d.obj.subKeys[e];b==f.getKeyId()&&(a[a.length]={obj:d.obj.getSubKeyAsKey(e),keyId:f.getKeyId()})}}return a};this.getPrivateKeyForKeyId=function(b){for(var a=[],c=0;c<this.privateKeys.length;c++)if(b==
+this.privateKeys[c].obj.getKeyId()&&(a[a.length]={key:this.privateKeys[c],keymaterial:this.privateKeys[c].obj.privateKeyPacket}),null!=this.privateKeys[c].obj.subKeys)for(var d=this.privateKeys[c].obj.getSubKeyIds(),e=0;e<d.length;e++)b==util.hexstrdump(d[e])&&(a[a.length]={key:this.privateKeys[c],keymaterial:this.privateKeys[c].obj.subKeys[e]});return a};this.importPublicKey=function(b){for(var a=openpgp.read_publicKey(b),c=0;c<a.length;c++)this.publicKeys[this.publicKeys.length]={armored:b,obj:a[c],
+keyId:a[c].getKeyId()};return!0};this.importPrivateKey=function(b,a){var c=openpgp.read_privateKey(b);if(!c[0].decryptSecretMPIs(a))return!1;for(var d=0;d<c.length;d++)this.privateKeys[this.privateKeys.length]={armored:b,obj:c[d],keyId:c[d].getKeyId()};return!0};this.exportPublicKey=function(b){return this.publicKey[b]};this.removePublicKey=function(b){b=this.publicKeys.splice(b,1);this.store();return b};this.exportPrivateKey=function(b){return this.privateKeys[b]};this.removePrivateKey=function(b){b=
+this.privateKeys.splice(b,1);this.store();return b}}
 function openpgp_msg_publickey(){this.tostring="OPENPGP PUBLIC KEY\n";this.publicKeyPacket=this.bindingSignature=null;this.userIds=[];this.userAttributes=[];this.revocationSignatures=[];this.subKeys=[];this.arbitraryPacket=[];this.directSignatures=[];this.verifyCertificationSignatures=function(){for(var b=[],a=0;a<this.userIds.length;a++)b[a]=this.userIds[a].verifyCertificationSignatures(this.publicKeyPacket);return b};this.getEncryptionKey=function(){if(17!=this.publicKeyPacket.publicKeyAlgorithm&&
 3!=this.publicKeyPacket.publicKeyAlgorithm&&this.publicKeyPacket.verifyKey())return this.publicKeyPacket;if(4==this.publicKeyPacket.version)for(var b=0;b<this.subKeys.length;b++)if(17!=this.subKeys[b].publicKeyAlgorithm&&3!=this.subKeys[b].publicKeyAlgorithm&&this.subKeys[b].verifyKey())return this.subKeys[b];return null};this.getSigningKey=function(){if(17==this.publicKeyPacket.publicKeyAlgorithm||2!=this.publicKeyPacket.publicKeyAlgorithm)return this.publicKeyPacket;if(4==this.publicKeyPacket.version)for(var b=
 0;b<this.subKeys.length;b++)if((17==this.subKeys[b].publicKeyAlgorithm||2!=this.subKeys[b].publicKeyAlgorithm)&&this.subKeys[b].verifyKey())return this.subKeys[b];return null};this.read_nodes=function(b,a,c,d){this.publicKeyPacket=b;for(b=c;a.length!=b;){var e=openpgp_packet.read_packet(a,b,a.length-b);if(null==e){util.print_error("openpgp.msg.publickey read_nodes:\n[pub_key]parsing ends here @:"+b+" l:"+d);break}else switch(e.tagType){case 2:32==e.signatureType?this.revocationSignatures[this.revocationSignatures.length]=
@@ -361,7 +362,7 @@ a.length-b);break;case 17:this.userAttributes[this.userAttributes.length]=e;b+=e
 return this.len=b-c};this.write=function(){};this.toString=function(){for(var b=" OPENPGP Public Key\n    length: "+this.len+"\n",b=b+"    Revocation Signatures:\n",a=0;a<this.revocationSignatures.length;a++)b+="    "+this.revocationSignatures[a].toString();b+="    User Ids:\n";for(a=0;a<this.userIds.length;a++)b+="    "+this.userIds[a].toString();b+="    User Attributes:\n";for(a=0;a<this.userAttributes.length;a++)b+="    "+this.userAttributes[a].toString();b+="    Public Key SubKeys:\n";for(a=0;a<
 this.subKeys.length;a++)b+="    "+this.subKeys[a].toString();return b};this.validate=function(){for(var b=0;b<this.revocationSignatures.length;b++)if(this.revocationSignatures[b].verify(this.publicKeyPacket.header+this.publicKeyPacket.data,this.publicKeyPacket))return!1;if(0!=this.subKeys.length){for(var a=!1,b=0;b<this.subKeys.length;b++)if(3==this.subKeys[b].verifyKey()){a=!0;break}if(!a)return!1}a=!1;for(b=0;b<this.userIds.length;b++)if(0==this.userIds[b].verify(this.publicKeyPacket)){a=!0;break}return!a?
 !1:!0};this.getFingerprint=function(){return this.publicKeyPacket.getFingerprint()};this.getKeyId=function(){return this.publicKeyPacket.getKeyId()};this.verifyBasicSignatures=function(){for(var b=0;b<this.revocationSignatures.length;b++)if(this.revocationSignatures[b].verify(this.publicKeyPacket.header+this.publicKeyPacket.data,this.publicKeyPacket))return!1;if(0!=this.subKeys.length){for(var a=!1,b=0;b<this.subKeys.length;b++)if(null!=this.subKeys[b]&&3==this.subKeys[b].verifyKey()){a=!0;break}if(!a)return!1}a=
-this.getKeyId();for(b=0;b<this.userIds.length;b++)for(var c=0;c<this.userIds[b].certificationRevocationSignatures.length;c++)if(this.userIds[b].certificationSignatures[c].getIssuer==a&&4!=this.userIds[b].certificationSignatures[c].verifyBasic(this.publicKeyPacket))return!1;return!0}}
+this.getKeyId();for(b=0;b<this.userIds.length;b++)for(var c=0;c<this.userIds[b].certificationRevocationSignatures.length;c++)if(this.userIds[b].certificationSignatures[c].getIssuer==a&&4!=this.userIds[b].certificationSignatures[c].verifyBasic(this.publicKeyPacket))return!1;return!0};this.getSubKeyAsKey=function(b){var a=new openpgp_msg_publickey;a.userIds=this.userIds;a.userAttributes=this.userAttributes;a.publicKeyPacket=this.subKeys[b];return a}}
 function openpgp_msg_message(){this.text="";this.type=this.messagePacket=null;this.decrypt=function(b,a){return this.decryptAndVerifySignature(b,a).text};this.decryptAndVerifySignature=function(b,a,c){if(null==b||null==a||""==a)return null;a=a.decrypt(this,b.keymaterial);if(null==a)return null;b=[];util.print_debug_hexstr_dump("openpgp.msg.messge decrypt:\n",a);var a=openpgp.read_messages_dearmored({text:a,openpgp:a}),d;for(d in a){if(a[d].data)this.text=a[d].data;a[d].signature&&b.push(a[d].verifySignature(c))}return{text:this.text,
 validSignatures:b}};this.verifySignature=function(b){var a=!1;if(2==this.signature.tagType){if(!b||0==b.length)if(4==this.signature.version)b=openpgp.keyring.getPublicKeysForKeyId(this.signature.issuerKeyId);else if(3==this.signature.version)b=openpgp.keyring.getPublicKeysForKeyId(this.signature.keyId);else return util.print_error("unknown signature type on message!"),!1;if(0==b.length)util.print_warning("Unable to verify signature of issuer: "+util.hexstrdump(this.signature.issuerKeyId)+". Public key not found in keyring.");
 else for(var c=0;c<b.length;c++)this.signature.verify(this.text.replace(/\r\n/g,"\n").replace(/\n/g,"\r\n"),b[c])?(util.print_info("Found Good Signature from "+b[c].obj.userIds[0].text+" (0x"+util.hexstrdump(b[c].obj.getKeyId()).substring(8)+")"),a=!0):util.print_error("Signature verification failed: Bad Signature from "+b[c].obj.userIds[0].text+" (0x"+util.hexstrdump(b[0].obj.getKeyId()).substring(8)+")")}return a};this.toString=function(){var b="Session Keys:\n";if(null!=this.sessionKeys)for(var a=
diff --git a/src/openpgp.keyring.js b/src/openpgp.keyring.js
index f4f1563e..d30e28d9 100644
--- a/src/openpgp.keyring.js
+++ b/src/openpgp.keyring.js
@@ -146,9 +146,22 @@ function openpgp_keyring() {
 	 */
 	function getPublicKeysForKeyId(keyId) {
 		var result = new Array();
-		for (var i=0; i < this.publicKeys.length; i++)
-			if (keyId == this.publicKeys[i].obj.getKeyId())
-				result[result.length] = this.publicKeys[i];
+		for (var i=0; i < this.publicKeys.length; i++) {
+			var key = this.publicKeys[i];
+			if (keyId == key.obj.getKeyId())
+				result[result.length] = key;
+			else if (key.obj.subKeys != null) {
+				for (var j=0; j < key.obj.subKeys.length; j++) {
+					var subkey = key.obj.subKeys[j];
+					if (keyId == subkey.getKeyId()) {
+						result[result.length] = {
+								obj: key.obj.getSubKeyAsKey(j),
+								keyId: subkey.getKeyId()
+						}
+					}
+				}
+			}
+		}
 		return result;
 	}
 	this.getPublicKeysForKeyId = getPublicKeysForKeyId;
diff --git a/src/openpgp.msg.publickey.js b/src/openpgp.msg.publickey.js
index ecd2b966..7d616cd1 100644
--- a/src/openpgp.msg.publickey.js
+++ b/src/openpgp.msg.publickey.js
@@ -243,6 +243,15 @@ function openpgp_msg_publickey() {
 		return null;
 	}
 
+        /* Returns the i-th subKey as a openpgp_msg_publickey object */
+	function getSubKeyAsKey(i) {
+		var ret = new openpgp_msg_publickey();
+		ret.userIds = this.userIds;
+		ret.userAttributes = this.userAttributes;
+		ret.publicKeyPacket = this.subKeys[i];
+		return ret;
+	}
+
 	this.getEncryptionKey = getEncryptionKey;
 	this.getSigningKey = getSigningKey;
 	this.read_nodes = read_nodes;
@@ -252,4 +261,5 @@ function openpgp_msg_publickey() {
 	this.getFingerprint = getFingerprint;
 	this.getKeyId = getKeyId;
 	this.verifyBasicSignatures = verifyBasicSignatures;
+	this.getSubKeyAsKey = getSubKeyAsKey;
 }
diff --git a/test/ciphers/openpgp.sigcheck.js b/test/ciphers/openpgp.sigcheck.js
index fbe89dd4..67b3de97 100644
--- a/test/ciphers/openpgp.sigcheck.js
+++ b/test/ciphers/openpgp.sigcheck.js
@@ -111,5 +111,57 @@ unittests.register("Testing of binary signature checking", function() {
   result[1] = new test_result("Testing GnuPG stripped-key extensions",
           priv_key_gnupg_ext[0].privateKeyPacket.s2k.type == 1001 &&
           ret.validSignatures[0] == true);
+
+  // Exercises the ability of openpgp_keyring.getPublicKeysForKeyId to return subkeys
+  var test_keyring = new openpgp_keyring();
+  test_keyring.init();
+  test_keyring.importPublicKey([
+        '-----BEGIN PGP PUBLIC KEY BLOCK-----',
+        'Version: GnuPG v1.4.11 (GNU/Linux)',
+        '',
+        'mQGiBFERvI4RBAD0M/HGglCtVNXPF72ehT8riAXrl0rSec4RJC61Bh+UAOhxn5+U',
+        'fDgos5p1SpIzYmn+M87JoSSVLAjfakFk0gHgR9I3bu7SIwq3Bikk1Vw3gO+yDSO6',
+        'TKpLUFGYDiBSSE1MGdxBadWLE1hlRf5B2x62gnGmjSpSVbly33PFkoDmrwCg9rAp',
+        'RmncnF9GhWjOLFkEoQw9Yx8EAOsxvq8Ig5Z1gk+ZKfDZeftpHRe3FdrRtbnhxvYY',
+        '7z+w9uz1EpoZUwDR5G4X3hTwJQ7lXmIOskg/+eRMLEAqEY7b/7tW6RaUJ2d6Ehsi',
+        'dOS89fIxElwjAOnVOM5S24f0FDQTTto7QBOoxcNTfkEJCHXSlpoOUmGAP85fXh3l',
+        'yPTGBACJfKc76Un3UWC1sWIRDxYiyh3ZpZyNEskoV6ESW8jEI1RnMnv5TrfGJH5K',
+        'E8jWX7TTnoFyPJtBTjlucAtkQaS4Bb7dg1LLja17zAqKNGOJK2b9fb2Z+lnTjPiY',
+        'i7DPH1XHnfaEexjlh/U7mYa5RrwIphRxNi8gCuxv874ZMmhEn7QWVGVzdDMgPHRl',
+        'c3QzQHRlc3QuY29tPohiBBMRAgAiBQJREbyOAhsDBgsJCAcDAgYVCAIJCgsEFgID',
+        'AQIeAQIXgAAKCRC0u8O0Moa2JYxyAJ9Oi2UlcUT0VJNgwjyl/VF9Xcjf9gCeJPvy',
+        'g/fp4EAU8MJIaN2yMI8pLFS5AaIEURG8nhEEAKVgeNDuYDPufLuJ0GrJV/CbXEjj',
+        'aEPA0iTUqV0nTCPdAfQ/nmE3gh5UlNMr/zSHJ+c4FQhYdLrzRGDOSzV+mfPHH3t+',
+        'YVx+wat0BYwABpHAtsIuLIVo2RQqYZYH85tatwBkm71HHT3jmlEAvr6NFH38+v3s',
+        '3w4Wl0/sdHyaeiSXAKCxJ4X1eOdN7L1rrbJozQ/gDCFuVQP/dcV6Ksss8Aw443jG',
+        'AYBLHWh6o4GhAY6/h1kijF0xD+uc+tNmTQnQi1tEOoTeIZMXnSRwtk8XEuJkkbAP',
+        '+uyvMgyV3wrk9zkaTAin7nrjAERxezFOdBEOtnB1CovJxtMn+RRxaMEGpC4GnETy',
+        'N5+6FkLuLcNXiCQP75ajzOAN1aID/juNjUNpBbNpfqBV7j1K+Kn0n9HYTyQl9ghy',
+        '026+/4c8ag2HV+bg3BD7c2VTVu9xBODHsfu0q8Ql/QB9W8tmYugU6DeXMHaeWPUH',
+        'ph98guM9kF2yHIiRBvAd5i7wOjwn+I/Ir6nBR2yxJ3p31CDUnUlbjTPYg7mtQvHW',
+        'EY2Cp4SWiJEEGBECAAkFAlERvJ4CGwIAUgkQtLvDtDKGtiVHIAQZEQIABgUCURG8',
+        'ngAKCRAMiMeR296Y2SjyAJ9V3wRJJ2Szazqal4khWGfLu5R6/wCfQQIRD24yVdz8',
+        '2a+2eCrwyALT2GAihACfS0nWM3a0gtITqngpJsRws+Ep+eIAn15qD2itutxNb8NI',
+        'bR2gBB5QmVJ3',
+        '=pGA6',
+        '-----END PGP PUBLIC KEY BLOCK-----'
+        ].join("\n"));
+
+  var msg2 = openpgp.read_message([
+        '-----BEGIN PGP MESSAGE-----',
+        'Version: GnuPG v1.4.11 (GNU/Linux)',
+        '',
+        'kA0DAAIRDIjHkdvemNkBrB1iB2Zvby50eHRREbz3VEVTVCBEQVRBIDEyMzQ1NohG',
+        'BAARAgAGBQJREbz3AAoJEAyIx5Hb3pjZ2TcAn32LpDEuHe9QrSRlyvSuREKNOFwz',
+        'AJ9zh4zsK4GIPuEu81YPNmHsju7DYg==',
+        '=WaSx',
+        '-----END PGP MESSAGE-----'
+        ].join("\n"));
+  var pubKey = test_keyring.getPublicKeysForKeyId(msg2[1].signature.issuerKeyId);
+  result[2] = new test_result("Testing keyring public subkey support",
+          pubKey != null && 
+          pubKey.length == 1 && 
+          msg2[1].signature.verify(msg2[0].data, pubKey[0]));
   return result;
 })
+