diff --git a/.gitattributes b/.gitattributes index 10783a7144fcc537bde39a9f73c20f7e4a62ffe9..74299ea3efcd7a0e9302009af4004a2b511cafb0 100644 --- a/.gitattributes +++ b/.gitattributes @@ -17,6 +17,7 @@ testfont binary /lib/modules/LR.pmod/priority.pike foreign_ident /lib/modules/LR.pmod/rule.pike foreign_ident /lib/modules/LR.pmod/scanner.pike foreign_ident +/lib/modules/SSL.pmod/asn1.pmod.pike foreign_ident /lib/modules/Sql.pmod/mysql.pike foreign_ident /lib/modules/Sql.pmod/mysql_result.pike foreign_ident /lib/modules/Sql.pmod/sql.pike foreign_ident diff --git a/lib/modules/SSL.pmod/asn1.pmod.pike b/lib/modules/SSL.pmod/asn1.pmod.pike new file mode 100644 index 0000000000000000000000000000000000000000..9e590d5e7f8d2d1410c1bf508076f703f4366c95 --- /dev/null +++ b/lib/modules/SSL.pmod/asn1.pmod.pike @@ -0,0 +1,110 @@ +/* asn1.pmod.pike + * + * Rudimentary support for decoding ASN.1 encoded data. + * + * $Id: asn1.pmod.pike,v 1.1 1997/03/15 04:46:01 nisse Exp $ + */ + +/* BER decoder + * + * Values are represented as arrays ({ tag, value }). + * Tag is either an integer tag number, or a string, in case + * the tag recognized. + * + * Values are strings, integers, or arrays */ + +class ber_decode { + inherit ADT.struct; + + array get_asn1() + { + int|string tag = get_int(1); + int len; + string contents; + mixed value; + + werror(sprintf("decoding tag %x\n", tag)); + if ( (tag & 0x1f) == 0x1f) + throw( ({ "high tag numbers is not supported\n", backtrace() }) ); + int len = get_int(1); + if (len & 0x80) + len = get_int(len & 0x7f); + + werror(sprintf("len : %d\n", len)); + + contents = get_fix_string(len); + werror(sprintf("contents: %O\n", contents)); + if (tag & 0x20) + { + object seq = object_program(this_object())(contents); + value = ({ }); + while(! seq->is_empty()) + { + array elem = seq->get_asn1(); + // werror(sprintf("elem: %O\n", elem)); + value += ({ elem }); + } + } + switch(tag & 0xdf) + { + case 1: /* Boolean */ + if (strlen(contents) != 1) + throw( ({ "SSL.asn1: Invalid boolean value.\n", backtrace() }) ); + tag = "BOOLEAN"; + value = !!contents[0]; + break; + case 2: /* Integer */ + tag = "INTEGER"; + value = Gmp.mpz(contents, 256); + if (contents[0] & 0x80) /* Negative */ + value -= Gmp.pow(256, strlen(contents)); + break; + case 3: /* Bit string */ + tag = "BIT STRING"; + break; + case 4: /* Octet string */ + tag = "OCTET STRING"; + break; + case 5: /* Null */ + if (strlen(contents)) + throw( ({ "SSL.asn1: Invalid NULL value.\n", backtrace() }) ); + break; + case 6: /* Object id */ + { + tag = "Identifier"; + if (value[0] <= 2) + value = ({ contents[0] / 40, contents[0] % 40 }); + else + value = ({ 2, contents[0] - 80 }); + int index = 1; + while(index < strlen(contents)) + { + int id = 0; + do + { + id = id << 7 | (contents[index] & 0x7f); + } while(contents[index++] & 0x80); + value += ({ id }); + } + break; + } + case 9: /* Real */ + tag = "REAL"; + break; + case 10: /* Enumerated */ + tag = "ENUMERATED"; + break; + case 16: /* Sequence */ + tag = "SEQUENCE"; + break; + case 17: /* Set */ + tag = "SET"; + break; + default: /* Keep numeric tag */ + break; + } + + return ({ tag, value }); + } +} + diff --git a/lib/modules/SSL.pmod/cipher.pike b/lib/modules/SSL.pmod/cipher.pike index 3e90eacf6140240e0db4701b5af8277ce0d962a3..c1fb2eda6ea039a8dcd7e3ab32129e5314358380 100644 --- a/lib/modules/SSL.pmod/cipher.pike +++ b/lib/modules/SSL.pmod/cipher.pike @@ -14,12 +14,14 @@ class CipherSpec { int iv_size; } +#if 0 class mac_none { /* Dummy MAC algorithm */ // string hash_raw(string data) { return ""; } string hash(string data, object seq_num) { return ""; } } +#endif class mac_sha { @@ -72,6 +74,7 @@ class mac_md5 { program algorithm = Crypto.md5; } +#if 0 class crypt_none { /* Dummy stream cipher */ @@ -79,6 +82,7 @@ class crypt_none object set_decrypt_key(string k) { return this_object(); } string crypt(string s) { return s; } } +#endif class des { @@ -143,7 +147,7 @@ array lookup(int suite) res->bulk_cipher_algorithm = Crypto.rc4; res->cipher_type = CIPHER_stream; res->is_exportable = 1; - res->key_material = 5; + res->key_material = 16; res->iv_size = 0; break; case CIPHER_des: @@ -168,7 +172,7 @@ array lookup(int suite) res->iv_size = 8; break; case CIPHER_null: - res->bulk_cipher_algorithm = crypt_none; + res->bulk_cipher_algorithm = 0; res->cipher_type = CIPHER_stream; res->is_exportable = 1; res->key_material = 0; @@ -189,7 +193,7 @@ array lookup(int suite) res->hash_size = 16; break; case 0: - res->mac_algorithm = mac_none; + res->mac_algorithm = 0; res->hash_size = 0; break; default: diff --git a/lib/modules/SSL.pmod/connection.pike b/lib/modules/SSL.pmod/connection.pike index d3e95429b1eb99ad7b354800f813a142bd0e2499..d5ccf40ff39349392ed2142661a4f62cbc90a3a7 100644 --- a/lib/modules/SSL.pmod/connection.pike +++ b/lib/modules/SSL.pmod/connection.pike @@ -15,7 +15,7 @@ int closing; inherit "constants"; inherit "handshake"; -constant Queue = (program) "queue"; +constant Queue = ADT.queue; constant State = (program) "state"; inherit Queue : alert; @@ -182,7 +182,7 @@ string|int got_data(string s) if (packet->is_alert) { /* Reply alert */ - werror("Bad recieved packet\n"); + werror("SSL.connection: Bad recieved packet\n"); send_packet(packet); if (packet->level == ALERT_fatal) return -1; diff --git a/lib/modules/SSL.pmod/context.pike b/lib/modules/SSL.pmod/context.pike index b5b3ad9fa9bf3de38e5675a451d234ea9d9a0614..e08b6352a9bf4163eda7b23c2a587c33f80d0521 100644 --- a/lib/modules/SSL.pmod/context.pike +++ b/lib/modules/SSL.pmod/context.pike @@ -28,7 +28,7 @@ array(int) preferred_suites = SSL_rsa_with_rc4_128_md5, SSL_rsa_with_3des_ede_cbc_sha, SSL_rsa_with_des_cbc_sha, -// SSL_rsa_export_with_rc4_40_md5, + SSL_rsa_export_with_rc4_40_md5, SSL_rsa_with_null_sha, SSL_rsa_with_null_md5 }); @@ -37,7 +37,7 @@ array(int) preferred_compressors = ({ COMPRESSION_null }); constant Session = (program) "session"; -constant Queue = (program) "queue"; +constant Queue = ADT.queue; int use_cache = 1; int session_lifetime = 600; /* Time to remember a session, in seconds */ diff --git a/lib/modules/SSL.pmod/handshake.pike b/lib/modules/SSL.pmod/handshake.pike index e8776e424515c66c7c66aedc0d0d304f273bf325..b7c99ea5178c27f8b328df9605019e8858932d82 100644 --- a/lib/modules/SSL.pmod/handshake.pike +++ b/lib/modules/SSL.pmod/handshake.pike @@ -37,7 +37,7 @@ int reuse; string my_random; string other_random; -constant Struct = (program) "struct"; +constant Struct = ADT.struct; constant Session = (program) "session"; constant Packet = (program) "packet"; constant Alert = (program) "alert"; @@ -76,16 +76,22 @@ int reply_new_session(array(int) cipher_suites, array(int) compression_methods) { reuse = 0; session = context->new_session(); - -// werror(sprintf("ciphers: me: %O, client: %O\n", -// context->preferred_suites, cipher_suites)); + multiset(int) common_suites; + + werror(sprintf("ciphers: me: %O, client: %O\n", + context->preferred_suites, cipher_suites)); // werror(sprintf("compr: me: %O, client: %O\n", // context->preferred_compressors, compression_methods)); - cipher_suites &= context->preferred_suites; - if (sizeof(cipher_suites)) - session->set_cipher_suite(cipher_suites[0]); - else + + common_suites = mkmultiset(cipher_suites & context->preferred_suites); + werror(sprintf("intersection: %O\n", common_suites)); + if (sizeof(common_suites)) { + int suite; + foreach(context->preferred_suites, suite) + if (common_suites[suite]) break; + session->set_cipher_suite(suite); + } else { send_packet(Alert(ALERT_fatal, ALERT_handshake_failure)); return -1; } @@ -245,11 +251,11 @@ int handle_handshake(int type, string data, string raw) "Version %d.%d hello detected\n", @version)); if (strlen(id)) - werror(sprintf("Looking up session %s\n", id)); + werror(sprintf("SSL.handshake: Looking up session %s\n", id)); session = strlen(id) && context->lookup_session(id); if (session) { - werror(sprintf("Reusing session %s\n", id)); + werror(sprintf("SSL.handshake: Reusing session %s\n", id)); /* Reuse session */ reuse = 1; if (! ( (cipher_suites & ({ session->cipher_suite })) diff --git a/lib/modules/SSL.pmod/https.pike b/lib/modules/SSL.pmod/https.pike index 1b73024001011eca298a70e129e2b29fe2681dc4..38379b83cd043c13c3d28a26a0ba5dd0bde0250d 100644 --- a/lib/modules/SSL.pmod/https.pike +++ b/lib/modules/SSL.pmod/https.pike @@ -90,10 +90,11 @@ class no_random { } } +#if 0 /* ad-hoc asn.1-decoder */ class ber_decode { - inherit "struct"; + inherit ADT.struct; array get_asn1() { @@ -128,6 +129,7 @@ class ber_decode { return ({ tag, contents }); } } +#endif /* PKCS#1 Private key structure: @@ -157,13 +159,13 @@ int main() werror(sprintf("Cert: '%s'\n", Crypto.string_to_hex(my_certificate))); werror(sprintf("Key: '%s'\n", Crypto.string_to_hex(my_key))); // werror(sprintf("Decoded cert: %O\n", ber_decode(my_certificate)->get_asn1())); - array key = ber_decode(my_key)->get_asn1()[1]; + array key = asn1.ber_decode(my_key)->get_asn1()[1]; werror(sprintf("Decoded key: %O\n", key)); - object n = Gmp.mpz(key[1][1], 256); - object e = Gmp.mpz(key[2][1], 256); - object d = Gmp.mpz(key[3][1], 256); - object p = Gmp.mpz(key[4][1], 256); - object q = Gmp.mpz(key[5][1], 256); + object n = key[1][1]; + object e = key[2][1]; + object d = key[3][1]; + object p = key[4][1]; + object q = key[5][1]; werror(sprintf("n = %s\np = %s\nq = %s\npq = %s\n", n->digits(), p->digits(), q->digits(), (p*q)->digits())); @@ -173,5 +175,11 @@ int main() certificates = ({ my_certificate }); random = no_random()->read; werror("Starting\n"); - return bind(PORT, my_accept_callback) ? -17 : 17; + if (!bind(PORT, my_accept_callback)) + { + perror(""); + return 17; + } + else + return -17; } diff --git a/lib/modules/SSL.pmod/sslport.pike b/lib/modules/SSL.pmod/sslport.pike index 47cc3303c8714201243e9d94bc0e30cdfe9ae560..18e8b25031d371d185f7baf61d2be1c32c42068f 100644 --- a/lib/modules/SSL.pmod/sslport.pike +++ b/lib/modules/SSL.pmod/sslport.pike @@ -90,11 +90,11 @@ class sslfile private void ssl_read_callback(mixed id, string s) { - werror(sprintf("sslfile->ssl_read_callback\n")); + werror(sprintf("SSL.sslfile->ssl_read_callback\n")); string|int data = got_data(s); if (stringp(data)) { - werror(sprintf("sslfile: application_data: '%s'\n", data)); + werror(sprintf("SSL.sslfile: application_data: '%s'\n", data)); if (strlen(data)) { read_buffer += data; diff --git a/lib/modules/SSL.pmod/state.pike b/lib/modules/SSL.pmod/state.pike index 13e19c194a3b0b3be2172a3a5f198ba0a793b59c..895445ef441c6c504261a34b9c52b2591182c22f 100644 --- a/lib/modules/SSL.pmod/state.pike +++ b/lib/modules/SSL.pmod/state.pike @@ -27,10 +27,12 @@ void create(object s) * there was an error, otherwise 0. */ object decrypt_packet(object packet) { + werror(sprintf("SSL.state->decrypt_packet: data = '%s'\n", packet->fragment)); + if (crypt) { string msg; -// werror("Trying decrypt..\n"); + werror("SSL.state: Trying decrypt..\n"); msg = crypt->crypt(packet->fragment); if (! msg) return Alert(ALERT_fatal, ALERT_unexpected_message); @@ -40,11 +42,11 @@ object decrypt_packet(object packet) packet->fragment = msg; } -// werror(sprintf("Decrypted_packet '%s'\n", packet->fragment)); + werror(sprintf("SSL.state: Decrypted_packet '%s'\n", packet->fragment)); if (mac) { -// werror("Trying mac verification...\n"); + werror("SSL.state: Trying mac verification...\n"); int length = strlen(packet->fragment) - session->cipher_spec->hash_size; string digest = packet->fragment[length ..]; packet->fragment = packet->fragment[.. length - 1]; @@ -56,7 +58,7 @@ object decrypt_packet(object packet) if (compress) { -// werror("Trying decompression...\n"); + werror("SSL.state: Trying decompression...\n"); string msg; msg = compress(packet->fragment); if (!msg)