diff --git a/resources/openpgp.js b/resources/openpgp.js index 6bf9af93..af77ac3a 100644 --- a/resources/openpgp.js +++ b/resources/openpgp.js @@ -7449,7 +7449,7 @@ function openpgp_config() { keyserver: "keyserver.linux.it" // "pgp.mit.edu:11371" }; - this.versionstring ="OpenPGP.js v.1.20130508"; + this.versionstring ="OpenPGP.js v.1.20130509"; this.commentstring ="http://openpgpjs.org"; /** * Reads the config out of the HTML5 local storage @@ -10924,190 +10924,11 @@ function openpgp_packet_secret_key() { this.public_key.algorithm); } - /** - * Generates Debug output - * @return String which gives some information about the keymaterial - */ - function toString() { - var result = ""; - switch (this.tagType) { - case 6: - result += '5.5.1.1. Public-Key Packet (Tag 6)\n'+ - ' length: '+this.packetLength+'\n'+ - ' version: '+this.version+'\n'+ - ' creation time: '+this.creationTime+'\n'+ - ' expiration time: '+this.expiration+'\n'+ - ' publicKeyAlgorithm: '+this.publicKeyAlgorithm+'\n'; - break; - case 14: - result += '5.5.1.2. Public-Subkey Packet (Tag 14)\n'+ - ' length: '+this.packetLength+'\n'+ - ' version: '+this.version+'\n'+ - ' creation time: '+this.creationTime+'\n'+ - ' expiration time: '+this.expiration+'\n'+ - ' publicKeyAlgorithm: '+this.publicKeyAlgorithm+'\n'; - break; - case 5: - result +='5.5.1.3. Secret-Key Packet (Tag 5)\n'+ - ' length: '+this.packetLength+'\n'+ - ' version: '+this.publicKey.version+'\n'+ - ' creation time: '+this.publicKey.creationTime+'\n'+ - ' expiration time: '+this.publicKey.expiration+'\n'+ - ' publicKeyAlgorithm: '+this.publicKey.publicKeyAlgorithm+'\n'; - break; - case 7: - result += '5.5.1.4. Secret-Subkey Packet (Tag 7)\n'+ - ' length: '+this.packetLength+'\n'+ - ' version[1]: '+(this.version == 4)+'\n'+ - ' creationtime[4]: '+this.creationTime+'\n'+ - ' expiration[2]: '+this.expiration+'\n'+ - ' publicKeyAlgorithm: '+this.publicKeyAlgorithm+'\n'; - break; - default: - result += 'unknown key material packet\n'; - } - if (this.MPIs != null) { - result += "Public Key MPIs:\n"; - for (var i = 0; i < this.MPIs.length; i++) { - result += this.MPIs[i].toString(); - } - } - if (this.publicKey != null && this.publicKey.MPIs != null) { - result += "Public Key MPIs:\n"; - for (var i = 0; i < this.publicKey.MPIs.length; i++) { - result += this.publicKey.MPIs[i].toString(); - } - } - if (this.mpi != null) { - result += "Secret Key MPIs:\n"; - for (var i = 0; i < this.mpi.length; i++) { - result += this.mpi[i].toString(); - } - } - - if (this.subKeySignature != null) - result += "subKey Signature:\n"+this.subKeySignature.toString(); - - if (this.subKeyRevocationSignature != null ) - result += "subKey Revocation Signature:\n"+this.subKeyRevocationSignature.toString(); - return result; - } - - /** - * Continue parsing packets belonging to the key material such as signatures - * @param {Object} parent_node The parent object - * @param {String} bytes Input string to read the packet(s) from - * @param {Integer} position Start position for the parser - * @param {Integer} len Length of the packet(s) or remaining length of bytes - * @return {Integer} Length of nodes read - */ - function read_nodes(parent_node, bytes, position, len) { - this.parentNode = parent_node; - if (this.tagType == 14) { // public sub-key packet - var pos = position; - var result = null; - while (bytes.length != pos) { - var l = bytes.length - pos; - result = openpgp_packet.read_packet(bytes, pos, l); - if (result == null) { - util.print_error("openpgp.packet.keymaterial.js\n"+'[user_keymat_pub]parsing ends here @:' + pos + " l:" + l); - break; - } else { - - switch (result.tagType) { - case 2: // Signature Packet certification signature - if (result.signatureType == 24) { // subkey binding signature - this.subKeySignature = result; - pos += result.packetLength + result.headerLength; - break; - } else if (result.signatureType == 40) { // subkey revocation signature - this.subKeyRevocationSignature[this.subKeyRevocationSignature.length] = result; - pos += result.packetLength + result.headerLength; - break; - } else { - util.print_error("openpgp.packet.keymaterial.js\nunknown signature:"+result.toString()); - } - - default: - this.data = bytes; - this.position = position - this.parentNode.packetLength; - this.len = pos - position; - return this.len; - break; - } - } - } - this.data = bytes; - this.position = position - this.parentNode.packetLength; - this.len = pos - position; - return this.len; - } else if (this.tagType == 7) { // private sub-key packet - var pos = position; - while (bytes.length != pos) { - var result = openpgp_packet.read_packet(bytes, pos, len - (pos - position)); - if (result == null) { - util.print_error("openpgp.packet.keymaterial.js\n"+'[user_keymat_priv] parsing ends here @:' + pos); - break; - } else { - switch (result.tagType) { - case 2: // Signature Packet certification signature - if (result.signatureType == 24) // subkey embedded signature - this.subKeySignature = result; - else if (result.signatureType == 40) // subkey revocation signature - this.subKeyRevocationSignature[this.subKeyRevocationSignature.length] = result; - pos += result.packetLength + result.headerLength; - break; - default: - this.data = bytes; - this.position = position - this.parentNode.packetLength; - this.len = pos - position; - return this.len; - } - } - } - this.data = bytes; - this.position = position - this.parentNode.packetLength; - this.len = pos - position; - return this.len; - } else { - util.print_error("openpgp.packet.keymaterial.js\n"+"unknown parent node for a key material packet "+parent_node.tagType); - } - } - - /** - * Checks the validity for usage of this (sub)key - * @return {Integer} 0 = bad key, 1 = expired, 2 = revoked, 3 = valid - */ - function verifyKey() { - if (this.tagType == 14) { - if (this.subKeySignature == null) { - return 0; - } - if (this.subKeySignature.version == 4 && - this.subKeySignature.keyNeverExpires != null && - !this.subKeySignature.keyNeverExpires && - new Date((this.subKeySignature.keyExpirationTime*1000)+ this.creationTime.getTime()) < new Date()) { - return 1; - } - var hashdata = String.fromCharCode(0x99)+this.parentNode.header.substring(1)+this.parentNode.data+ - String.fromCharCode(0x99)+this.header.substring(1)+this.packetdata; - if (!this.subKeySignature.verify(hashdata,this.parentNode)) { - return 0; - } - for (var i = 0; i < this.subKeyRevocationSignature.length; i++) { - if (this.getKeyId() == this.subKeyRevocationSignature[i].keyId){ - return 2; - } - } - } - return 3; - } - /** * Calculates the key id of they key * @return {String} A 8 byte key id */ - function getKeyId() { + this.getKeyId = function() { if (this.version == 4) { var f = this.getFingerprint(); return f.substring(12,20); @@ -11122,7 +10943,7 @@ function openpgp_packet_secret_key() { * Calculates the fingerprint of the key * @return {String} A string containing the fingerprint */ - function getFingerprint() { + this.getFingerprint = function() { if (this.version == 4) { tohash = String.fromCharCode(0x99)+ String.fromCharCode(((this.packetdata.length) >> 8) & 0xFF) + String.fromCharCode((this.packetdata.length) & 0xFF)+this.packetdata; @@ -11132,8 +10953,6 @@ function openpgp_packet_secret_key() { return MD5(this.MPIs[0].MPI); } } - - } @@ -11523,6 +11342,79 @@ function openpgp_packet_signature() { } }; + this.toSign = function(type, data) { + var t = openpgp_packet_signature.type; + + switch(type) { + case t.binary: + return data.literal.get_data_bytes(); + + case t.text: + return toSign(t.binary, data) + .replace(/\r\n/g, '\n') + .replace(/\n/g, '\r\n'); + + case t.standalone: + return '' + + case t.cert_generic: + case t.cert_persona: + case t.cert_casual: + case t.cert_positive: + case t.cert_revocation: + { + var packet, tag; + + if(data.userid != undefined) { + tag = 0xB4; + packet = data.userid; + } + else if(data.userattribute != undefined) { + tag = 0xD1 + packet = data.userattribute; + } + else throw new Error('Either a userid or userattribute packet needs to be ' + + 'supplied for certification.'); + + + var bytes = packet.write(); + + + return this.toSign(t.key, data) + + String.fromCharCode(tag) + + openpgp_packet_number_write(bytes.length, 4) + + bytes; + } + case t.subkey_binding: + case t.key_binding: + { + return this.toSign(t.key, data) + this.toSign(t.key, { key: data.bind }); + } + case t.key: + { + if(data.key == undefined) + throw new Error('Key packet is required for this sigtature.'); + + var bytes = data.key.write(); + + return String.fromCharCode(0x99) + + openpgp_packet_number_write(bytes.length, 2) + + bytes; + } + case t.key_revocation: + case t.subkey_revocation: + return this.toSign(t.key, data); + case t.timestamp: + return ''; + case t.thrid_party: + throw new Error('Not implemented'); + break; + default: + throw new Error('Unknown signature type.') + } + } + + /** * verifys the signature packet. Note: not signature types are implemented * @param {String} data data which on the signature applies @@ -11531,65 +11423,7 @@ function openpgp_packet_signature() { */ this.verify = function(key, data) { - var bytes = - - (function(type, data) { - switch(type) { - case 0: // 0x00: Signature of a binary document. - return data.literal.data; - break; - - case 1: // 0x01: Signature of a canonical text document. - return data.replace(/\r\n/g, '\n').replace(/\n/g, '\r\n'); - - case 2: // 0x02: Standalone signature. - return '' - case 16: - // 0x10: Generic certification of a User ID and Public-Key packet. - case 17: - // 0x11: Persona certification of a User ID and Public-Key packet. - case 18: - // 0x12: Casual certification of a User ID and Public-Key packet. - case 19: - // 0x13: Positive certification of a User ID and Public-Key packet. - case 48: - // 0x30: Certification revocation signature - - if(data.userid != undefined) { - return String.fromCharCode(0xB4) + - openpgp_packet_number_write(data.userid.userid.length, 4) + - data; - } - else if(data.userattribute != undefined) { - return String.fromCharCode(0xB4) + - openpgp_packet_number_write(data.userattribute.userid.length, 4) + - data; - } - else return; - case 24: - // 0x18: Subkey Binding Signature - break; - case 25: - // 0x19: Primary Key Binding Signature - case 31: - // 0x1F: Signature directly on a key - case 32: - // 0x20: Key revocation signature - case 40: - // 0x28: Subkey revocation signature - return; - case 64: - // 0x40: Timestamp signature. - break; - case 80: - // 0x50: Third-Party Confirmation signature. - break; - default: - util.print_error("openpgp.packet.signature.js\n"+ - "signature verification for type"+ - this.signatureType+" not implemented"); - return false; - }})(this.signatureType, data); + var bytes = this.toSign(this.signatureType, data); // calculating the trailer var trailer = ''; @@ -11606,7 +11440,7 @@ function openpgp_packet_signature() { } -/* One pass signature packet type +/** One pass signature packet type * @enum {Integer} */ openpgp_packet_signature.type = { /** 0x00: Signature of a binary document. */ diff --git a/resources/openpgp.min.js b/resources/openpgp.min.js index 9799818f..f2ccf999 100644 --- a/resources/openpgp.min.js +++ b/resources/openpgp.min.js @@ -285,7 +285,7 @@ JXG.Util.asciiCharCodeAt=function(a,b){var c=a.charCodeAt(b);if(255d?(b.push(String.fromCharCode(d)),c++):191d?(e=a.charCodeAt(c+1),b.push(String.fromCharCode((d&31)<<6|e&63)),c+=2):(e=a.charCodeAt(c+1),f=a.charCodeAt(c+2),b.push(String.fromCharCode((d&15)<<12|(e&63)<<6|f&63)),c+=3);return b.join("")}; JXG.Util.genUUID=function(){for(var a="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".split(""),b=Array(36),c=0,d,e=0;36>e;e++)8==e||13==e||18==e||23==e?b[e]="-":14==e?b[e]="4":(2>=c&&(c=33554432+16777216*Math.random()|0),d=c&15,c>>=4,b[e]=a[19==e?d&3|8:d]);return b.join("")}; -function openpgp_config(){this.config=null;this.default_config={prefer_hash_algorithm:8,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.20130508";this.commentstring="http://openpgpjs.org";this.debug=!1;this.read=function(){var a=JSON.parse(window.localStorage.getItem("config"));null==a?(this.config=this.default_config,this.write()):this.config=a};this.write=function(){window.localStorage.setItem("config", +function openpgp_config(){this.config=null;this.default_config={prefer_hash_algorithm:8,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.20130509";this.commentstring="http://openpgpjs.org";this.debug=!1;this.read=function(){var a=JSON.parse(window.localStorage.getItem("config"));null==a?(this.config=this.default_config,this.write()):this.config=a};this.write=function(){window.localStorage.setItem("config", JSON.stringify(this.config))}}var b64s="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";function s2r(a){var b,c,d,e="",f=0,h=0,g=a.length;for(d=0;d>2&63),b=(c&3)<<4):1==h?(e+=b64s.charAt(b|c>>4&15),b=(c&15)<<2):2==h&&(e+=b64s.charAt(b|c>>6&3),f+=1,0==f%60&&(e+="\n"),e+=b64s.charAt(c&63)),f+=1,0==f%60&&(e+="\n"),h+=1,3==h&&(h=0);0>6-e&255)),e=e+2&7,f=b<this.publicKeyAlgorithm){var a=this.MPIs[0].substring(this.MPIs[0].mpiByteLength-8);util.print_debug("openpgp.msg.publickey read_nodes:\nV3 key ID: "+a);return a}};this.getFingerprint=function(){if(4==this.version)return tohash=String.fromCharCode(153)+String.fromCharCode(this.packetdata.length>>8&255)+String.fromCharCode(this.packetdata.length&255)+this.packetdata,util.print_debug("openpgp.msg.publickey creating subkey fingerprint by hashing:"+ +util.hexstrdump(tohash)+"\npublickeyalgorithm: "+this.publicKeyAlgorithm),str_sha1(tohash,tohash.length);if(3==this.version&&0this.publicKeyAlgorithm)return MD5(this.MPIs[0].MPI)}}function openpgp_packet_secret_subkey(){openpgp_packet_secret_key.call(this);this.tag=7} function openpgp_packet_signature(){this.tag=2;this.issuerKeyId=this.revocationKeyFingerprint=this.revocationKeyAlgorithm=this.revocationKeyClass=this.preferredSymmetricAlgorithms=this.keyNeverExpires=this.keyExpirationTime=this.revocable=this.regularExpression=this.trustAmount=this.trustLevel=this.exportable=this.hashAlgorithm=this.publicKeyAlgorithm=this.mpi=this.signedHashValue=this.signatureNeverExpires=this.signatureExpirationTime=this.signatureData=this.created=this.signatureType=null;this.notation= {};this.embeddedSignature=this.signatureTargetHash=this.signatureTargetHashAlgorithm=this.signatureTargetPublicKeyAlgorithm=this.reasonForRevocationString=this.reasonForRevocationFlag=this.signersUserId=this.keyFlags=this.policyURI=this.isPrimaryUserID=this.preferredKeyServer=this.keyServerPreferences=this.preferredCompressionAlgorithms=this.preferredHashAlgorithms=null;this.verified=!1;this.read=function(a){var b=0;this.version=a[b++].charCodeAt();switch(this.version){case 3:5!=a[b++].charCodeAt()&& util.print_debug("openpgp.packet.signature.js\ninvalid One-octet length of following hashed material.MUST be 5. @:"+(b-1));this.signatureType=a[b++].charCodeAt();this.created=openpgp_packet_time_read(a.substr(b,4));b+=4;this.signatureData=a.substring(position,b);this.issuerKeyId=a.substring(b,b+8);b+=8;this.publicKeyAlgorithm=a[b++].charCodeAt();this.hashAlgorithm=a[b++].charCodeAt();break;case 4:this.signatureType=a[b++].charCodeAt();this.publicKeyAlgorithm=a[b++].charCodeAt();this.hashAlgorithm= @@ -394,9 +395,10 @@ a[b++].charCodeAt();var c=function(a,b){for(var c=openpgp_packet_number_read(a.s a;break;case 4:this.exportable=1==a[c++].charCodeAt();break;case 5:this.trustLevel=a[c++].charCodeAt();this.trustAmount=a[c++].charCodeAt();break;case 6:this.regularExpression=a.substr(c);break;case 7:this.revocable=1==a[c++].charCodeAt();break;case 9:this.keyExpirationTime=a=openpgp_packet_time_read(a.substr(c));this.keyNeverExpires=0==a.getTime();break;case 11:for(this.preferredSymmetricAlgorithms=[];c!=a.length;)this.preferredSymmetricAlgorithms.push(a[c++].charCodeAt());break;case 12:this.revocationKeyClass= a[c++].charCodeAt();this.revocationKeyAlgorithm=a[c++].charCodeAt();this.revocationKeyFingerprint=a.substr(c,20);break;case 16:this.issuerKeyId=a.substr(c,8);break;case 20:if(128==a[c].charCodeAt()){var c=c+4,e=openpgp_packet_number_read(a.substr(c,2)),c=c+2,f=openpgp_packet_number_read(a.substr(c,2)),c=c+2,d=a.substr(c,e),a=a.substr(c+e,f);this.notation[d]=a}break;case 21:b.call(this,"preferredHashAlgorithms",a.substr(c));break;case 22:b.call(this,"preferredCompressionAlgorithms ",a.substr(c));break; case 23:b.call(this,"keyServerPreferencess",a.substr(c));break;case 24:this.preferredKeyServer=a.substr(c);break;case 25:this.isPrimaryUserID=0!=a[c++];break;case 26:this.policyURI=a.substr(c);break;case 27:b.call(this,"keyFlags",a.substr(c));break;case 28:this.signersUserId+=a.substr(c);break;case 29:this.reasonForRevocationFlag=a[c++].charCodeAt();this.reasonForRevocationString=a.substr(c);break;case 30:b.call(this,"features",a.substr(c));break;case 31:this.signatureTargetPublicKeyAlgorithm=a[c++].charCodeAt(); -this.signatureTargetHashAlgorithm=a[c++].charCodeAt();e=openpgp_crypto_getHashByteLength(this.signatureTargetHashAlgorithm);this.signatureTargetHash=a.substr(c,e);break;case 32:this.embeddedSignature=new openpgp_packet_signature;this.embeddedSignature.read(a.substr(c));break;default:util.print_error("openpgp.packet.signature.js\nunknown signature subpacket type "+d+" @:"+c+" subplen:"+subplen+" len:"+e)}};this.verify=function(a,b){var c=function(a,b){switch(a){case 0:return b.literal.data;case 1:return b.replace(/\r\n/g, -"\n").replace(/\n/g,"\r\n");case 2:return"";case 16:case 17:case 18:case 19:case 48:if(void 0!=b.userid)return String.fromCharCode(180)+openpgp_packet_number_write(b.userid.userid.length,4)+b;if(void 0!=b.userattribute)return String.fromCharCode(180)+openpgp_packet_number_write(b.userattribute.userid.length,4)+b;break;case 24:break;case 25:case 31:case 32:case 40:break;case 64:break;case 80:break;default:return util.print_error("openpgp.packet.signature.js\nsignature verification for type"+this.signatureType+ -" not implemented"),!1}}(this.signatureType,b),d;d=""+String.fromCharCode(this.version);d+=String.fromCharCode(255);d+=openpgp_packet_number_write(this.signatureData.length,4);return this.verified=openpgp_crypto_verifySignature(this.publicKeyAlgorithm,this.hashAlgorithm,this.mpi,a.mpi,c+this.signatureData+d)}} +this.signatureTargetHashAlgorithm=a[c++].charCodeAt();e=openpgp_crypto_getHashByteLength(this.signatureTargetHashAlgorithm);this.signatureTargetHash=a.substr(c,e);break;case 32:this.embeddedSignature=new openpgp_packet_signature;this.embeddedSignature.read(a.substr(c));break;default:util.print_error("openpgp.packet.signature.js\nunknown signature subpacket type "+d+" @:"+c+" subplen:"+subplen+" len:"+e)}};this.toSign=function(a,b){var c=openpgp_packet_signature.type;switch(a){case c.binary:return b.literal.get_data_bytes(); +case c.text:return toSign(c.binary,b).replace(/\r\n/g,"\n").replace(/\n/g,"\r\n");case c.standalone:return"";case c.cert_generic:case c.cert_persona:case c.cert_casual:case c.cert_positive:case c.cert_revocation:var d,e;if(void 0!=b.userid)e=180,d=b.userid;else if(void 0!=b.userattribute)e=209,d=b.userattribute;else throw Error("Either a userid or userattribute packet needs to be supplied for certification.");d=d.write();return this.toSign(c.key,b)+String.fromCharCode(e)+openpgp_packet_number_write(d.length, +4)+d;case c.subkey_binding:case c.key_binding:return this.toSign(c.key,b)+this.toSign(c.key,{key:b.bind});case c.key:if(void 0==b.key)throw Error("Key packet is required for this sigtature.");d=b.key.write();return String.fromCharCode(153)+openpgp_packet_number_write(d.length,2)+d;case c.key_revocation:case c.subkey_revocation:return this.toSign(c.key,b);case c.timestamp:return"";case c.thrid_party:throw Error("Not implemented");default:throw Error("Unknown signature type.");}};this.verify=function(a, +b){var c=this.toSign(this.signatureType,b),d;d=""+String.fromCharCode(this.version);d+=String.fromCharCode(255);d+=openpgp_packet_number_write(this.signatureData.length,4);return this.verified=openpgp_crypto_verifySignature(this.publicKeyAlgorithm,this.hashAlgorithm,this.mpi,a.mpi,c+this.signatureData+d)}} openpgp_packet_signature.type={binary:0,text:1,standalone:2,cert_generic:16,cert_persona:17,cert_casual:18,cert_positive:19,cert_revocation:48,subkey_binding:24,key_binding:25,key:31,key_revocation:32,subkey_revocation:40,timestamp:64,third_party:80}; function openpgp_packet_sym_encrypted_integrity_protected(){this.tag=18;this.version=1;this.encrypted=null;this.modification=!1;this.packets=new openpgp_packetlist;this.read=function(a){this.version=a[0].charCodeAt();if(1!=this.version)return util.print_error("openpgp.packet.encryptedintegrityprotecteddata.js\nunknown encrypted integrity protected data packet version: "+this.version+"hex:"+util.hexstrdump(a)),null;this.encrypted=a.substr(1)};this.write=function(){return String.fromCharCode(this.version)+ this.encrypted};this.encrypt=function(a,b){var c=this.packets.write(),d=openpgp_crypto_getPrefixRandom(a),e=d+d.charAt(d.length-2)+d.charAt(d.length-1),c=c+String.fromCharCode(211),c=c+String.fromCharCode(20);util.print_debug_hexstr_dump("data to be hashed:",e+c);c+=str_sha1(e+c);util.print_debug_hexstr_dump("hash:",c.substring(c.length-20,c.length));this.encrypted=openpgp_crypto_symmetricEncrypt(d,a,b,c,!1).substring(0,e.length+c.length)};this.decrypt=function(a,b){var c=openpgp_crypto_symmetricDecrypt(a, diff --git a/src/packet/secret_key.js b/src/packet/secret_key.js index c533d8c4..3d50210c 100644 --- a/src/packet/secret_key.js +++ b/src/packet/secret_key.js @@ -340,190 +340,11 @@ function openpgp_packet_secret_key() { this.public_key.algorithm); } - /** - * Generates Debug output - * @return String which gives some information about the keymaterial - */ - function toString() { - var result = ""; - switch (this.tagType) { - case 6: - result += '5.5.1.1. Public-Key Packet (Tag 6)\n'+ - ' length: '+this.packetLength+'\n'+ - ' version: '+this.version+'\n'+ - ' creation time: '+this.creationTime+'\n'+ - ' expiration time: '+this.expiration+'\n'+ - ' publicKeyAlgorithm: '+this.publicKeyAlgorithm+'\n'; - break; - case 14: - result += '5.5.1.2. Public-Subkey Packet (Tag 14)\n'+ - ' length: '+this.packetLength+'\n'+ - ' version: '+this.version+'\n'+ - ' creation time: '+this.creationTime+'\n'+ - ' expiration time: '+this.expiration+'\n'+ - ' publicKeyAlgorithm: '+this.publicKeyAlgorithm+'\n'; - break; - case 5: - result +='5.5.1.3. Secret-Key Packet (Tag 5)\n'+ - ' length: '+this.packetLength+'\n'+ - ' version: '+this.publicKey.version+'\n'+ - ' creation time: '+this.publicKey.creationTime+'\n'+ - ' expiration time: '+this.publicKey.expiration+'\n'+ - ' publicKeyAlgorithm: '+this.publicKey.publicKeyAlgorithm+'\n'; - break; - case 7: - result += '5.5.1.4. Secret-Subkey Packet (Tag 7)\n'+ - ' length: '+this.packetLength+'\n'+ - ' version[1]: '+(this.version == 4)+'\n'+ - ' creationtime[4]: '+this.creationTime+'\n'+ - ' expiration[2]: '+this.expiration+'\n'+ - ' publicKeyAlgorithm: '+this.publicKeyAlgorithm+'\n'; - break; - default: - result += 'unknown key material packet\n'; - } - if (this.MPIs != null) { - result += "Public Key MPIs:\n"; - for (var i = 0; i < this.MPIs.length; i++) { - result += this.MPIs[i].toString(); - } - } - if (this.publicKey != null && this.publicKey.MPIs != null) { - result += "Public Key MPIs:\n"; - for (var i = 0; i < this.publicKey.MPIs.length; i++) { - result += this.publicKey.MPIs[i].toString(); - } - } - if (this.mpi != null) { - result += "Secret Key MPIs:\n"; - for (var i = 0; i < this.mpi.length; i++) { - result += this.mpi[i].toString(); - } - } - - if (this.subKeySignature != null) - result += "subKey Signature:\n"+this.subKeySignature.toString(); - - if (this.subKeyRevocationSignature != null ) - result += "subKey Revocation Signature:\n"+this.subKeyRevocationSignature.toString(); - return result; - } - - /** - * Continue parsing packets belonging to the key material such as signatures - * @param {Object} parent_node The parent object - * @param {String} bytes Input string to read the packet(s) from - * @param {Integer} position Start position for the parser - * @param {Integer} len Length of the packet(s) or remaining length of bytes - * @return {Integer} Length of nodes read - */ - function read_nodes(parent_node, bytes, position, len) { - this.parentNode = parent_node; - if (this.tagType == 14) { // public sub-key packet - var pos = position; - var result = null; - while (bytes.length != pos) { - var l = bytes.length - pos; - result = openpgp_packet.read_packet(bytes, pos, l); - if (result == null) { - util.print_error("openpgp.packet.keymaterial.js\n"+'[user_keymat_pub]parsing ends here @:' + pos + " l:" + l); - break; - } else { - - switch (result.tagType) { - case 2: // Signature Packet certification signature - if (result.signatureType == 24) { // subkey binding signature - this.subKeySignature = result; - pos += result.packetLength + result.headerLength; - break; - } else if (result.signatureType == 40) { // subkey revocation signature - this.subKeyRevocationSignature[this.subKeyRevocationSignature.length] = result; - pos += result.packetLength + result.headerLength; - break; - } else { - util.print_error("openpgp.packet.keymaterial.js\nunknown signature:"+result.toString()); - } - - default: - this.data = bytes; - this.position = position - this.parentNode.packetLength; - this.len = pos - position; - return this.len; - break; - } - } - } - this.data = bytes; - this.position = position - this.parentNode.packetLength; - this.len = pos - position; - return this.len; - } else if (this.tagType == 7) { // private sub-key packet - var pos = position; - while (bytes.length != pos) { - var result = openpgp_packet.read_packet(bytes, pos, len - (pos - position)); - if (result == null) { - util.print_error("openpgp.packet.keymaterial.js\n"+'[user_keymat_priv] parsing ends here @:' + pos); - break; - } else { - switch (result.tagType) { - case 2: // Signature Packet certification signature - if (result.signatureType == 24) // subkey embedded signature - this.subKeySignature = result; - else if (result.signatureType == 40) // subkey revocation signature - this.subKeyRevocationSignature[this.subKeyRevocationSignature.length] = result; - pos += result.packetLength + result.headerLength; - break; - default: - this.data = bytes; - this.position = position - this.parentNode.packetLength; - this.len = pos - position; - return this.len; - } - } - } - this.data = bytes; - this.position = position - this.parentNode.packetLength; - this.len = pos - position; - return this.len; - } else { - util.print_error("openpgp.packet.keymaterial.js\n"+"unknown parent node for a key material packet "+parent_node.tagType); - } - } - - /** - * Checks the validity for usage of this (sub)key - * @return {Integer} 0 = bad key, 1 = expired, 2 = revoked, 3 = valid - */ - function verifyKey() { - if (this.tagType == 14) { - if (this.subKeySignature == null) { - return 0; - } - if (this.subKeySignature.version == 4 && - this.subKeySignature.keyNeverExpires != null && - !this.subKeySignature.keyNeverExpires && - new Date((this.subKeySignature.keyExpirationTime*1000)+ this.creationTime.getTime()) < new Date()) { - return 1; - } - var hashdata = String.fromCharCode(0x99)+this.parentNode.header.substring(1)+this.parentNode.data+ - String.fromCharCode(0x99)+this.header.substring(1)+this.packetdata; - if (!this.subKeySignature.verify(hashdata,this.parentNode)) { - return 0; - } - for (var i = 0; i < this.subKeyRevocationSignature.length; i++) { - if (this.getKeyId() == this.subKeyRevocationSignature[i].keyId){ - return 2; - } - } - } - return 3; - } - /** * Calculates the key id of they key * @return {String} A 8 byte key id */ - function getKeyId() { + this.getKeyId = function() { if (this.version == 4) { var f = this.getFingerprint(); return f.substring(12,20); @@ -538,7 +359,7 @@ function openpgp_packet_secret_key() { * Calculates the fingerprint of the key * @return {String} A string containing the fingerprint */ - function getFingerprint() { + this.getFingerprint = function() { if (this.version == 4) { tohash = String.fromCharCode(0x99)+ String.fromCharCode(((this.packetdata.length) >> 8) & 0xFF) + String.fromCharCode((this.packetdata.length) & 0xFF)+this.packetdata; @@ -548,8 +369,6 @@ function openpgp_packet_secret_key() { return MD5(this.MPIs[0].MPI); } } - - } diff --git a/src/packet/signature.js b/src/packet/signature.js index 87d3862e..182068d2 100644 --- a/src/packet/signature.js +++ b/src/packet/signature.js @@ -378,6 +378,79 @@ function openpgp_packet_signature() { } }; + this.toSign = function(type, data) { + var t = openpgp_packet_signature.type; + + switch(type) { + case t.binary: + return data.literal.get_data_bytes(); + + case t.text: + return toSign(t.binary, data) + .replace(/\r\n/g, '\n') + .replace(/\n/g, '\r\n'); + + case t.standalone: + return '' + + case t.cert_generic: + case t.cert_persona: + case t.cert_casual: + case t.cert_positive: + case t.cert_revocation: + { + var packet, tag; + + if(data.userid != undefined) { + tag = 0xB4; + packet = data.userid; + } + else if(data.userattribute != undefined) { + tag = 0xD1 + packet = data.userattribute; + } + else throw new Error('Either a userid or userattribute packet needs to be ' + + 'supplied for certification.'); + + + var bytes = packet.write(); + + + return this.toSign(t.key, data) + + String.fromCharCode(tag) + + openpgp_packet_number_write(bytes.length, 4) + + bytes; + } + case t.subkey_binding: + case t.key_binding: + { + return this.toSign(t.key, data) + this.toSign(t.key, { key: data.bind }); + } + case t.key: + { + if(data.key == undefined) + throw new Error('Key packet is required for this sigtature.'); + + var bytes = data.key.write(); + + return String.fromCharCode(0x99) + + openpgp_packet_number_write(bytes.length, 2) + + bytes; + } + case t.key_revocation: + case t.subkey_revocation: + return this.toSign(t.key, data); + case t.timestamp: + return ''; + case t.thrid_party: + throw new Error('Not implemented'); + break; + default: + throw new Error('Unknown signature type.') + } + } + + /** * verifys the signature packet. Note: not signature types are implemented * @param {String} data data which on the signature applies @@ -386,65 +459,7 @@ function openpgp_packet_signature() { */ this.verify = function(key, data) { - var bytes = - - (function(type, data) { - switch(type) { - case 0: // 0x00: Signature of a binary document. - return data.literal.data; - break; - - case 1: // 0x01: Signature of a canonical text document. - return data.replace(/\r\n/g, '\n').replace(/\n/g, '\r\n'); - - case 2: // 0x02: Standalone signature. - return '' - case 16: - // 0x10: Generic certification of a User ID and Public-Key packet. - case 17: - // 0x11: Persona certification of a User ID and Public-Key packet. - case 18: - // 0x12: Casual certification of a User ID and Public-Key packet. - case 19: - // 0x13: Positive certification of a User ID and Public-Key packet. - case 48: - // 0x30: Certification revocation signature - - if(data.userid != undefined) { - return String.fromCharCode(0xB4) + - openpgp_packet_number_write(data.userid.userid.length, 4) + - data; - } - else if(data.userattribute != undefined) { - return String.fromCharCode(0xB4) + - openpgp_packet_number_write(data.userattribute.userid.length, 4) + - data; - } - else return; - case 24: - // 0x18: Subkey Binding Signature - break; - case 25: - // 0x19: Primary Key Binding Signature - case 31: - // 0x1F: Signature directly on a key - case 32: - // 0x20: Key revocation signature - case 40: - // 0x28: Subkey revocation signature - return; - case 64: - // 0x40: Timestamp signature. - break; - case 80: - // 0x50: Third-Party Confirmation signature. - break; - default: - util.print_error("openpgp.packet.signature.js\n"+ - "signature verification for type"+ - this.signatureType+" not implemented"); - return false; - }})(this.signatureType, data); + var bytes = this.toSign(this.signatureType, data); // calculating the trailer var trailer = ''; diff --git a/test/general/packet.js b/test/general/packet.js index df1d7917..da7003ba 100644 --- a/test/general/packet.js +++ b/test/general/packet.js @@ -335,7 +335,8 @@ unittests.register("Packet testing", function() { var verified = key[2].verify(key[0].public_key, { - userid: key[1] + userid: key[1], + key: key[0].public_key });