diff options
Diffstat (limited to 'school/node_modules/node-forge/tests')
45 files changed, 10650 insertions, 0 deletions
diff --git a/school/node_modules/node-forge/tests/aes-speed.js b/school/node_modules/node-forge/tests/aes-speed.js new file mode 100644 index 0000000..2049a8a --- /dev/null +++ b/school/node_modules/node-forge/tests/aes-speed.js @@ -0,0 +1,62 @@ +var forge = require('../js/forge'); + +console.log('Times in 1000s of bytes/sec processed.'); + +aes_128('AES-CBC'); +aes_128('AES-CFB'); +aes_128('AES-OFB'); +aes_128('AES-CTR'); +aes_128('AES-GCM'); + +function aes_128(algorithm) { + console.log('Running ' + algorithm + ' for 5 seconds...'); + + var size = 1024; + var key = forge.random.getBytesSync(16); + var iv = forge.random.getBytes(algorithm === 'AES-GCM' ? 12 : 16); + var plain = forge.random.getBytesSync(size); + + // run for 5 seconds + var start = new Date().getTime(); + + var now; + var totalEncrypt = 0; + var totalDecrypt = 0; + var cipher; + var count = 0; + var passed = 0; + while(passed < 5000) { + var input = forge.util.createBuffer(plain); + + // encrypt, only measuring update() and finish() + cipher = forge.cipher.createCipher(algorithm, key); + cipher.start({iv: iv}); + now = new Date().getTime(); + cipher.update(input); + cipher.finish(); + totalEncrypt += new Date().getTime() - now; + + var ciphertext = cipher.output; + var tag = cipher.mode.tag; + count += cipher.output.length(); + + // decrypt, only measuring update() and finish() + cipher = forge.cipher.createDecipher(algorithm, key); + cipher.start({iv: iv, tag: tag}); + now = new Date().getTime(); + cipher.update(ciphertext); + if(!cipher.finish()) { + throw new Error('Decryption error.'); + } + totalDecrypt += new Date().getTime() - now; + + passed = new Date().getTime() - start; + } + + count = count / 1000; + totalEncrypt /= 1000; + totalDecrypt /= 1000; + console.log('encrypt: ' + (count / totalEncrypt) + ' k/sec'); + console.log('decrypt: ' + (count / totalDecrypt) + ' k/sec'); + console.log(); +} diff --git a/school/node_modules/node-forge/tests/common.html b/school/node_modules/node-forge/tests/common.html new file mode 100644 index 0000000..0fb4705 --- /dev/null +++ b/school/node_modules/node-forge/tests/common.html @@ -0,0 +1,84 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head> + <title>Forge Common Test</title> + <link type="text/css" rel="stylesheet" media="all" href="screen.css" /> + <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script> + <script type="text/javascript" src="forge/debug.js"></script> + <script type="text/javascript" src="forge/util.js"></script> + <script type="text/javascript" src="forge/log.js"></script> + <script type="text/javascript" src="forge/task.js"></script> + <script type="text/javascript" src="forge/md5.js"></script> + <script type="text/javascript" src="forge/sha1.js"></script> + <script type="text/javascript" src="forge/sha256.js"></script> + <script type="text/javascript" src="forge/hmac.js"></script> + <script type="text/javascript" src="forge/pbkdf2.js"></script> + <script type="text/javascript" src="forge/aes.js"></script> + <script type="text/javascript" src="forge/pem.js"></script> + <script type="text/javascript" src="forge/asn1.js"></script> + <script type="text/javascript" src="forge/jsbn.js"></script> + <script type="text/javascript" src="forge/prng.js"></script> + <script type="text/javascript" src="forge/random.js"></script> + <script type="text/javascript" src="forge/oids.js"></script> + <script type="text/javascript" src="forge/rsa.js"></script> + <script type="text/javascript" src="forge/pbe.js"></script> + <script type="text/javascript" src="forge/x509.js"></script> + <script type="text/javascript" src="forge/pki.js"></script> + <script type="text/javascript" src="forge/tls.js"></script> + <script type="text/javascript" src="forge/aesCipherSuites.js"></script> + <script type="text/javascript" src="common.js"></script> + + <link type="text/css" rel="stylesheet" media="all" href="screen.css" /> + <style type="text/css"> + .ready { color: inherit; background: inherit; } + .testing { color: black; background: yellow; } + .pass{ color: white; background: green; } + .fail{ color: white; background: red; } + </style> + </head> +<body> +<div class="nav"><a href="index.html">Forge Tests</a> / Common</div> + +<div class="header"> + <h1>Common Tests</h1> +</div> + +<div class="content"> + +<fieldset class="section"> + <ul> + <li>Test various Forge components.</li> + <li>See JavaScript console for more detailed output.</li> + </ul> +</fieldset> + +<fieldset class="section"> +<legend>Control</legend> + <button id="start">Start</button> + <button id="reset">Reset</button> + <br/> + <input id="scroll" type="checkbox" />Scroll Tests + <br/> + <button id="keygen">Generate RSA key pair</button> + <button id="certgen">Generate RSA certificate</button> + <input id="bits" value="1024"/>bits +</fieldset> + +<fieldset class="section"> +<legend>Progress</legend> +Status: <span id="status">?</span><br/> +Pass: <span id="pass">?</span>/<span id="total">?</span><br/> +Fail: <span id="fail">?</span> +</fieldset> + +<fieldset class="section"> +<legend>Tests</legend> +<div id="tests"></div> +</fieldset> + +</div> + +</body> +</html> diff --git a/school/node_modules/node-forge/tests/common.js b/school/node_modules/node-forge/tests/common.js new file mode 100644 index 0000000..57dfbc4 --- /dev/null +++ b/school/node_modules/node-forge/tests/common.js @@ -0,0 +1,2199 @@ +/** + * Forge Common Tests + * + * @author Dave Longley + * + * Copyright (c) 2009-2012 Digital Bazaar, Inc. All rights reserved. + */ +jQuery(function($) +{ + // logging category + var cat = 'forge.tests.common'; + + // local alias + var forge = window.forge; + + var tests = []; + var passed = 0; + var failed = 0; + + var init = function() + { + passed = failed = 0; + $('.ready,.testing,.pass,.fail') + .removeClass('ready testing pass fail'); + $('#status') + .text('Ready.') + .addClass('ready'); + $('#total').text(tests.length); + $('#pass').text(passed); + $('#fail').text(failed); + $('.expect').empty(); + $('.result').empty(); + $('.time').empty(); + $('.timePer').empty(); + $('#start').attr('disabled', ''); + }; + + var start = function() + { + $('#start').attr('disabled', 'true'); + // meta! use tasks to run the task tests + forge.task.start({ + type: 'test', + run: function(task) { + task.next('starting', function(task) { + forge.log.debug(cat, 'start'); + $('#status') + .text('Testing...') + .addClass('testing') + .removeClass('idle'); + }); + $.each(tests, function(i, test) { + task.next('test', function(task) { + var title = $('li:first', test.container); + if($('#scroll:checked').length === 1) + { + $('html,body').animate({scrollTop: title.offset().top}); + } + title.addClass('testing'); + test.run(task, test); + }); + task.next('test', function(task) { + $('li:first', test.container).removeClass('testing'); + }); + }); + task.next('success', function(task) { + forge.log.debug(cat, 'done'); + if(failed === 0) { + $('#status') + .text('PASS') + .addClass('pass') + .removeClass('testing'); + } else { + // FIXME: should just be hitting failure() below + $('#status') + .text('FAIL') + .addClass('fail') + .removeClass('testing'); + } + }); + }, + failure: function() { + $('#status') + .text('FAIL') + .addClass('fail') + .removeClass('testing'); + } + }); + }; + + $('#start').click(function() { + start(); + }); + + $('#reset').click(function() { + init(); + }); + + $('#keygen').click(function() { + var bits = $('#bits')[0].value; + var keys = forge.pki.rsa.generateKeyPair(bits); + forge.log.debug(cat, 'generating ' + bits + '-bit RSA key-pair...'); + setTimeout(function() + { + forge.log.debug(cat, 'private key:', keys.privateKey); + forge.log.debug(cat, forge.pki.privateKeyToPem(keys.privateKey)); + forge.log.debug(cat, 'public key:', keys.publicKey); + forge.log.debug(cat, forge.pki.publicKeyToPem(keys.publicKey)); + + forge.log.debug(cat, 'testing sign/verify...'); + setTimeout(function() + { + // do sign/verify test + try + { + var md = forge.md.sha1.create(); + md.update('foo'); + var signature = keys.privateKey.sign(md); + keys.publicKey.verify(md.digest().getBytes(), signature); + forge.log.debug(cat, 'sign/verify success'); + } + catch(ex) + { + forge.log.error(cat, 'sign/verify failure', ex); + } + }, 0); + }, 0); + }); + + $('#certgen').click(function() { + var bits = $('#bits')[0].value; + forge.log.debug(cat, 'generating ' + bits + + '-bit RSA key-pair and certificate...'); + setTimeout(function() + { + try + { + var keys = forge.pki.rsa.generateKeyPair(bits); + var cert = forge.pki.createCertificate(); + cert.serialNumber = '01'; + cert.validity.notBefore = new Date(); + cert.validity.notAfter = new Date(); + cert.validity.notAfter.setFullYear( + cert.validity.notBefore.getFullYear() + 1); + var attrs = [{ + name: 'commonName', + value: 'mycert' + }, { + name: 'countryName', + value: 'US' + }, { + shortName: 'ST', + value: 'Virginia' + }, { + name: 'localityName', + value: 'Blacksburg' + }, { + name: 'organizationName', + value: 'Test' + }, { + shortName: 'OU', + value: 'Test' + }]; + cert.setSubject(attrs); + cert.setIssuer(attrs); + cert.setExtensions([{ + name: 'basicConstraints', + cA: true + }, { + name: 'keyUsage', + keyCertSign: true + }, { + name: 'subjectAltName', + altNames: [{ + type: 6, // URI + value: 'http://localhost/dataspace/person/myname#this' + }] + }]); + // FIXME: add subjectKeyIdentifier extension + // FIXME: add authorityKeyIdentifier extension + cert.publicKey = keys.publicKey; + + // self-sign certificate + cert.sign(keys.privateKey); + + forge.log.debug(cat, 'certificate:', cert); + //forge.log.debug(cat, + // forge.asn1.prettyPrint(forge.pki.certificateToAsn1(cert))); + forge.log.debug(cat, forge.pki.certificateToPem(cert)); + + // verify certificate + forge.log.debug(cat, 'verified', cert.verify(cert)); + } + catch(ex) + { + forge.log.error(cat, ex, ex.message ? ex.message : ''); + } + }, 0); + }); + + var addTest = function(name, run) + { + var container = $('<ul><li>Test ' + name + '</li><ul/></ul>'); + var expect = $('<li>Expect: <span class="expect"/></li>'); + var result = $('<li>Result: <span class="result"/></li>'); + var time = $('<li>Time: <span class="time"/></li>'); + var timePer = $('<li>Time Per Iteration: <span class="timePer"/></li>'); + $('ul', container) + .append(expect) + .append(result) + .append(time) + .append(timePer); + $('#tests').append(container); + var test = { + container: container, + startTime: null, + run: function(task, test) { + test.startTime = new Date(); + run(task, test); + }, + expect: $('span', expect), + result: $('span', result), + check: function() { + var e = test.expect.text(); + var r = test.result.text(); + (e == r) ? test.pass() : test.fail(); + }, + pass: function(iterations) { + var dt = new Date() - test.startTime; + if(!iterations) + { + iterations = 1; + } + var dti = (dt / iterations); + passed += 1; + $('#pass').text(passed); + $('li:first', container).addClass('pass'); + $('span.time', container).html(dt + 'ms'); + $('span.timePer', container).html(dti + 'ms'); + }, + fail: function(iterations) { + var dt = new Date() - test.startTime; + if(!iterations) + { + iterations = 1; + } + var dti = (dt / iterations); + failed += 1; + $('#fail').text(failed); + $('li:first', container).addClass('fail'); + $('span.time', container).html(dt + 'ms'); + $('span.timePer', container).html(dti + 'ms'); + } + }; + tests.push(test); + }; + + addTest('buffer put bytes', function(task, test) + { + ba = forge.util.createBuffer(); + ba.putByte(1); + ba.putByte(2); + ba.putByte(3); + ba.putByte(4); + ba.putInt32(4); + ba.putByte(1); + ba.putByte(2); + ba.putByte(3); + ba.putInt32(4294967295); + var hex = ba.toHex(); + var bytes = []; + while(ba.length() > 0) + { + bytes.push(ba.getByte()); + } + var expect = [1, 2, 3, 4, 0, 0, 0, 4, 1, 2, 3, 255, 255, 255, 255]; + var exHex = '0102030400000004010203ffffffff'; + test.expect.html(exHex); + test.result.html(hex); + + test.check(); + }); + + addTest('buffer from hex', function(task, test) + { + var exHex = '0102030400000004010203ffffffff'; + test.expect.html(exHex); + + var buf = forge.util.createBuffer(); + buf.putBytes(forge.util.hexToBytes(exHex)); + test.result.html(buf.toHex()); + + test.check(); + }); + + addTest('base64 encode', function(task, test) + { + var s1 = '00010203050607080A0B0C0D0F1011121415161719'; + var s2 = 'MDAwMTAyMDMwNTA2MDcwODBBMEIwQzBEMEYxMDExMTIxNDE1MTYxNzE5'; + test.expect.html(s2); + + var out = forge.util.encode64(s1); + test.result.html(out); + + test.check(); + }); + + addTest('base64 decode', function(task, test) + { + var s1 = '00010203050607080A0B0C0D0F1011121415161719'; + var s2 = 'MDAwMTAyMDMwNTA2MDcwODBBMEIwQzBEMEYxMDExMTIxNDE1MTYxNzE5'; + test.expect.html(s1); + + var out = forge.util.decode64(s2); + test.result.html(out); + + test.check(); + }); + + addTest('md5 empty', function(task, test) + { + var expect = 'd41d8cd98f00b204e9800998ecf8427e'; + test.expect.html(expect); + var md = forge.md.md5.create(); + test.result.html(md.digest().toHex()); + test.check(); + }); + + addTest('md5 "abc"', function(task, test) + { + var expect = '900150983cd24fb0d6963f7d28e17f72'; + test.expect.html(expect); + var md = forge.md.md5.create(); + md.update('abc'); + test.result.html(md.digest().toHex()); + test.check(); + }); + + addTest('md5 "The quick brown fox jumps over the lazy dog"', + function(task, test) + { + var expect = '9e107d9d372bb6826bd81d3542a419d6'; + test.expect.html(expect); + var md = forge.md.md5.create(); + md.start(); + md.update('The quick brown fox jumps over the lazy dog'); + test.result.html(md.digest().toHex()); + test.check(); + }); + + // c'รจ + addTest('md5 "c\'\u00e8"', function(task, test) + { + var expect = '8ef7c2941d78fe89f31e614437c9db59'; + test.expect.html(expect); + var md = forge.md.md5.create(); + md.update("c'\u00e8", 'utf8'); + test.result.html(md.digest().toHex()); + test.check(); + }); + + addTest('md5 "THIS IS A MESSAGE"', + function(task, test) + { + var expect = '78eebfd9d42958e3f31244f116ab7bbe'; + test.expect.html(expect); + var md = forge.md.md5.create(); + md.start(); + md.update('THIS IS '); + md.update('A MESSAGE'); + // do twice to check continuing digest + test.result.html(md.digest().toHex()); + test.result.html(md.digest().toHex()); + test.check(); + }); + + addTest('md5 long message', + function(task, test) + { + var input = forge.util.createBuffer(); + input.putBytes(forge.util.hexToBytes( + '0100002903018d32e9c6dc423774c4c39a5a1b78f44cc2cab5f676d39' + + 'f703d29bfa27dfeb870000002002f0100')); + input.putBytes(forge.util.hexToBytes( + '0200004603014c2c1e835d39da71bc0857eb04c2b50fe90dbb2a8477f' + + 'e7364598d6f0575999c20a6c7248c5174da6d03ac711888f762fc4ed5' + + '4f7254b32273690de849c843073d002f00')); + input.putBytes(forge.util.hexToBytes( + '0b0003d20003cf0003cc308203c8308202b0a003020102020100300d0' + + '6092a864886f70d0101050500308186310b3009060355040613025553' + + '311d301b060355040a13144469676974616c2042617a6161722c20496' + + 'e632e31443042060355040b133b4269746d756e6b206c6f63616c686f' + + '73742d6f6e6c7920436572746966696361746573202d20417574686f7' + + '2697a6174696f6e207669612042545031123010060355040313096c6f' + + '63616c686f7374301e170d3130303231343137303931395a170d32303' + + '03231333137303931395a308186310b3009060355040613025553311d' + + '301b060355040a13144469676974616c2042617a6161722c20496e632' + + 'e31443042060355040b133b4269746d756e6b206c6f63616c686f7374' + + '2d6f6e6c7920436572746966696361746573202d20417574686f72697' + + 'a6174696f6e207669612042545031123010060355040313096c6f6361' + + '6c686f737430820122300d06092a864886f70d01010105000382010f0' + + '03082010a0282010100dc436f17d6909d8a9d6186ea218eb5c86b848b' + + 'ae02219bd56a71203daf07e81bc19e7e98134136bcb012881864bf03b' + + '3774652ad5eab85dba411a5114ffeac09babce75f31314345512cd87c' + + '91318b2e77433270a52185fc16f428c3ca412ad6e9484bc2fb87abb4e' + + '8fb71bf0f619e31a42340b35967f06c24a741a31c979c0bb8921a90a4' + + '7025fbeb8adca576979e70a56830c61170c9647c18c0794d68c0df38f' + + '3aac5fc3b530e016ea5659715339f3f3c209cdee9dbe794b5af92530c' + + '5754c1d874b78974bfad994e0dfc582275e79feb522f6e4bcc2b2945b' + + 'aedfb0dbdaebb605f9483ff0bea29ecd5f4d6f2769965d1b3e04f8422' + + '716042680011ff676f0203010001a33f303d300c0603551d130101ff0' + + '4023000300e0603551d0f0101ff0404030204f0301d0603551d250416' + + '301406082b0601050507030106082b06010505070302300d06092a864' + + '886f70d010105050003820101009c4562be3f2d8d8e388085a697f2f1' + + '06eaeff4992a43f198fe3dcf15c8229cf1043f061a38204f73d86f4fb' + + '6348048cc5279ed719873aa10e3773d92b629c2c3fcce04012c81ba3b' + + '4ec451e9644ec5191078402d845e05d02c7b4d974b4588276e5037aba' + + '7ef26a8bddeb21e10698c82f425e767dc401adf722fa73ab78cfa069b' + + 'd69052d7ca6a75cc9225550e315d71c5f8764362ea4dbc6ecb837a847' + + '1043c5a7f826a71af145a053090bd4bccca6a2c552841cdb1908a8352' + + 'f49283d2e641acdef667c7543af441a16f8294251e2ac376fa507b53a' + + 'e418dd038cd20cef1e7bfbf5ae03a7c88d93d843abaabbdc5f3431132' + + 'f3e559d2dd414c3eda38a210b8')); + input.putBytes(forge.util.hexToBytes('0e000000')); + input.putBytes(forge.util.hexToBytes( + '10000102010026a220b7be857402819b78d81080d01a682599bbd0090' + + '2985cc64edf8e520e4111eb0e1729a14ffa3498ca259cc9ad6fc78fa1' + + '30d968ebdb78dc0b950c0aa44355f13ba678419185d7e4608fe178ca6' + + 'b2cef33e4193778d1a70fe4d0dfcb110be4bbb4dbaa712177655728f9' + + '14ab4c0f6c4aef79a46b3d996c82b2ebe9ed1748eb5cace7dc44fb67e' + + '73f452a047f2ed199b3d50d5db960acf03244dc8efa4fc129faf8b65f' + + '9e52e62b5544722bd17d2358e817a777618a4265a3db277fc04851a82' + + 'a91fe6cdcb8127f156e0b4a5d1f54ce2742eb70c895f5f8b85f5febe6' + + '9bc73e891f9280826860a0c2ef94c7935e6215c3c4cd6b0e43e80cca3' + + '96d913d36be')); + + var expect = 'd15a2da0e92c3da55dc573f885b6e653'; + test.expect.html(expect); + + var md = forge.md.md5.create(); + md.start(); + md.update(input.getBytes()); + test.result.html(md.digest().toHex()); + + test.check(); + }); + + addTest('sha-1 empty', function(task, test) + { + var expect = 'da39a3ee5e6b4b0d3255bfef95601890afd80709'; + test.expect.html(expect); + var md = forge.md.sha1.create(); + test.result.html(md.digest().toHex()); + test.check(); + }); + + addTest('sha-1 "abc"', function(task, test) + { + var expect = 'a9993e364706816aba3e25717850c26c9cd0d89d'; + test.expect.html(expect); + var md = forge.md.sha1.create(); + md.update('abc'); + test.result.html(md.digest().toHex()); + test.check(); + }); + + addTest('sha-1 "The quick brown fox jumps over the lazy dog"', + function(task, test) + { + var expect = '2fd4e1c67a2d28fced849ee1bb76e7391b93eb12'; + test.expect.html(expect); + var md = forge.md.sha1.create(); + md.start(); + md.update('The quick brown fox jumps over the lazy dog'); + test.result.html(md.digest().toHex()); + test.check(); + }); + + // c'รจ + addTest('sha-1 "c\'\u00e8"', function(task, test) + { + var expect = '98c9a3f804daa73b68a5660d032499a447350c0d'; + test.expect.html(expect); + var md = forge.md.sha1.create(); + md.update("c'\u00e8", 'utf8'); + test.result.html(md.digest().toHex()); + test.check(); + }); + + addTest('sha-1 "THIS IS A MESSAGE"', + function(task, test) + { + var expect = '5f24f4d6499fd2d44df6c6e94be8b14a796c071d'; + test.expect.html(expect); + var md = forge.md.sha1.create(); + md.start(); + md.update('THIS IS '); + md.update('A MESSAGE'); + // do twice to check continuing digest + test.result.html(md.digest().toHex()); + test.result.html(md.digest().toHex()); + test.check(); + }); + + // other browsers too slow for this test + if($.browser.webkit) + { + addTest('sha-1 long message', + function(task, test) + { + var expect = '34aa973cd4c4daa4f61eeb2bdbad27316534016f'; + test.expect.html(expect); + var md = forge.md.sha1.create(); + md.start(); + md.update(forge.util.fillString('a', 1000000)); + // do twice to check continuing digest + test.result.html(md.digest().toHex()); + test.result.html(md.digest().toHex()); + test.check(); + }); + } + + addTest('sha-256 "abc"', function(task, test) + { + var expect = + 'ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad'; + test.expect.html(expect); + var md = forge.md.sha256.create(); + md.update('abc'); + test.result.html(md.digest().toHex()); + test.check(); + }); + + // c'รจ + addTest('sha-256 "c\'\u00e8"', function(task, test) + { + var expect = + '1aa15c717afffd312acce2217ce1c2e5dabca53c92165999132ec9ca5decdaca'; + test.expect.html(expect); + var md = forge.md.sha256.create(); + md.update("c'\u00e8", 'utf8'); + test.result.html(md.digest().toHex()); + test.check(); + }); + + addTest('sha-256 "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"', + function(task, test) + { + var expect = + '248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1'; + test.expect.html(expect); + var md = forge.md.sha256.create(); + md.start(); + md.update('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq'); + test.result.html(md.digest().toHex()); + test.check(); + }); + + // other browsers too slow for this test + if($.browser.webkit) + { + addTest('sha-256 long message', + function(task, test) + { + var expect = + 'cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0'; + test.expect.html(expect); + var md = forge.md.sha256.create(); + md.start(); + md.update(forge.util.fillString('a', 1000000)); + // do twice to check continuing digest + test.result.html(md.digest().toHex()); + test.result.html(md.digest().toHex()); + test.check(); + }); + } + + addTest('hmac md5 "Hi There", 16-byte key', function(task, test) + { + var expect = '9294727a3638bb1c13f48ef8158bfc9d'; + test.expect.html(expect); + var key = forge.util.hexToBytes( + '0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b'); + var hmac = forge.hmac.create(); + hmac.start('MD5', key); + hmac.update('Hi There'); + test.result.html(hmac.digest().toHex()); + test.check(); + }); + + addTest('hmac md5 "what do ya want for nothing?", "Jefe" key', + function(task, test) + { + var expect = '750c783e6ab0b503eaa86e310a5db738'; + test.expect.html(expect); + var hmac = forge.hmac.create(); + hmac.start('MD5', 'Jefe'); + hmac.update('what do ya want for nothing?'); + test.result.html(hmac.digest().toHex()); + test.check(); + }); + + addTest('hmac md5 "Test Using Larger Than Block-Size Key - ' + + 'Hash Key First", 80-byte key', function(task, test) + { + var expect = '6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd'; + test.expect.html(expect); + var key = forge.util.hexToBytes( + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'); + var hmac = forge.hmac.create(); + hmac.start('MD5', key); + hmac.update('Test Using Larger Than Block-Size Key - Hash Key First'); + test.result.html(hmac.digest().toHex()); + test.check(); + }); + + addTest('hmac sha-1 "Hi There", 20-byte key', function(task, test) + { + var expect = 'b617318655057264e28bc0b6fb378c8ef146be00'; + test.expect.html(expect); + var key = forge.util.hexToBytes( + '0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b'); + var hmac = forge.hmac.create(); + hmac.start('SHA1', key); + hmac.update('Hi There'); + test.result.html(hmac.digest().toHex()); + test.check(); + }); + + addTest('hmac sha-1 "what do ya want for nothing?", "Jefe" key', + function(task, test) + { + var expect = 'effcdf6ae5eb2fa2d27416d5f184df9c259a7c79'; + test.expect.html(expect); + var hmac = forge.hmac.create(); + hmac.start('SHA1', 'Jefe'); + hmac.update('what do ya want for nothing?'); + test.result.html(hmac.digest().toHex()); + test.check(); + }); + + addTest('hmac sha-1 "Test Using Larger Than Block-Size Key - ' + + 'Hash Key First", 80-byte key', function(task, test) + { + var expect = 'aa4ae5e15272d00e95705637ce8a3b55ed402112'; + test.expect.html(expect); + var key = forge.util.hexToBytes( + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'); + var hmac = forge.hmac.create(); + hmac.start('SHA1', key); + hmac.update('Test Using Larger Than Block-Size Key - Hash Key First'); + test.result.html(hmac.digest().toHex()); + test.check(); + }); + + addTest('pbkdf2 hmac-sha-1 c=1', function(task, test) + { + var expect = '0c60c80f961f0e71f3a9b524af6012062fe037a6'; + var dk = forge.pkcs5.pbkdf2('password', 'salt', 1, 20); + test.expect.html(expect); + test.result.html(forge.util.bytesToHex(dk)); + test.check(); + }); + + addTest('pbkdf2 hmac-sha-1 c=2', function(task, test) + { + var expect = 'ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957'; + var dk = forge.pkcs5.pbkdf2('password', 'salt', 2, 20); + test.expect.html(expect); + test.result.html(forge.util.bytesToHex(dk)); + test.check(); + }); + + addTest('pbkdf2 hmac-sha-1 c=2', function(task, test) + { + var expect = 'ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957'; + var dk = forge.pkcs5.pbkdf2('password', 'salt', 2, 20); + test.expect.html(expect); + test.result.html(forge.util.bytesToHex(dk)); + test.check(); + }); + + addTest('pbkdf2 hmac-sha-1 c=5 keylen=8', function(task, test) + { + var expect = 'd1daa78615f287e6'; + var salt = forge.util.hexToBytes('1234567878563412'); + var dk = forge.pkcs5.pbkdf2('password', salt, 5, 8); + test.expect.html(expect); + test.result.html(forge.util.bytesToHex(dk)); + test.check(); + }); + + // other browsers too slow for this test + if($.browser.webkit) + { + addTest('pbkdf2 hmac-sha-1 c=4096', function(task, test) + { + var expect = '4b007901b765489abead49d926f721d065a429c1'; + var dk = forge.pkcs5.pbkdf2('password', 'salt', 4096, 20); + test.expect.html(expect); + test.result.html(forge.util.bytesToHex(dk)); + test.check(); + }); + } + + /* too slow for javascript + addTest('pbkdf2 hmac-sha-1 c=16777216', function(task, test) + { + var expect = 'eefe3d61cd4da4e4e9945b3d6ba2158c2634e984'; + var dk = forge.pkcs5.pbkdf2('password', 'salt', 16777216, 20); + test.expect.html(expect); + test.result.html(forge.util.bytesToHex(dk)); + test.check(); + });*/ + + addTest('aes-128 encrypt', function(task, test) + { + var block = []; + block.push(0x00112233); + block.push(0x44556677); + block.push(0x8899aabb); + block.push(0xccddeeff); + var plain = block; + + var key = []; + key.push(0x00010203); + key.push(0x04050607); + key.push(0x08090a0b); + key.push(0x0c0d0e0f); + + var expect = []; + expect.push(0x69c4e0d8); + expect.push(0x6a7b0430); + expect.push(0xd8cdb780); + expect.push(0x70b4c55a); + + test.expect.html('69c4e0d86a7b0430d8cdb78070b4c55a'); + + var output = []; + var w = forge.aes._expandKey(key, false); + forge.aes._updateBlock(w, block, output, false); + + var out = forge.util.createBuffer(); + out.putInt32(output[0]); + out.putInt32(output[1]); + out.putInt32(output[2]); + out.putInt32(output[3]); + test.result.html(out.toHex()); + + test.check(); + }); + + addTest('aes-128 decrypt', function(task, test) + { + var block = []; + block.push(0x69c4e0d8); + block.push(0x6a7b0430); + block.push(0xd8cdb780); + block.push(0x70b4c55a); + + var key = []; + key.push(0x00010203); + key.push(0x04050607); + key.push(0x08090a0b); + key.push(0x0c0d0e0f); + + var expect = []; + expect.push(0x00112233); + expect.push(0x44556677); + expect.push(0x8899aabb); + expect.push(0xccddeeff); + + test.expect.html('00112233445566778899aabbccddeeff'); + + var output = []; + w = forge.aes._expandKey(key, true); + forge.aes._updateBlock(w, block, output, true); + + var out = forge.util.createBuffer(); + out.putInt32(output[0]); + out.putInt32(output[1]); + out.putInt32(output[2]); + out.putInt32(output[3]); + test.result.html(out.toHex()); + + test.check(); + }); + + addTest('aes-192 encrypt', function(task, test) + { + var block = []; + block.push(0x00112233); + block.push(0x44556677); + block.push(0x8899aabb); + block.push(0xccddeeff); + var plain = block; + + var key = []; + key.push(0x00010203); + key.push(0x04050607); + key.push(0x08090a0b); + key.push(0x0c0d0e0f); + key.push(0x10111213); + key.push(0x14151617); + + var expect = []; + expect.push(0xdda97ca4); + expect.push(0x864cdfe0); + expect.push(0x6eaf70a0); + expect.push(0xec0d7191); + + test.expect.html('dda97ca4864cdfe06eaf70a0ec0d7191'); + + var output = []; + var w = forge.aes._expandKey(key, false); + forge.aes._updateBlock(w, block, output, false); + + var out = forge.util.createBuffer(); + out.putInt32(output[0]); + out.putInt32(output[1]); + out.putInt32(output[2]); + out.putInt32(output[3]); + test.result.html(out.toHex()); + + test.check(); + }); + + addTest('aes-192 decrypt', function(task, test) + { + var block = []; + block.push(0xdda97ca4); + block.push(0x864cdfe0); + block.push(0x6eaf70a0); + block.push(0xec0d7191); + + var key = []; + key.push(0x00010203); + key.push(0x04050607); + key.push(0x08090a0b); + key.push(0x0c0d0e0f); + key.push(0x10111213); + key.push(0x14151617); + + var expect = []; + expect.push(0x00112233); + expect.push(0x44556677); + expect.push(0x8899aabb); + expect.push(0xccddeeff); + + test.expect.html('00112233445566778899aabbccddeeff'); + + var output = []; + w = forge.aes._expandKey(key, true); + forge.aes._updateBlock(w, block, output, true); + + var out = forge.util.createBuffer(); + out.putInt32(output[0]); + out.putInt32(output[1]); + out.putInt32(output[2]); + out.putInt32(output[3]); + test.result.html(out.toHex()); + + test.check(); + }); + + addTest('aes-256 encrypt', function(task, test) + { + var block = []; + block.push(0x00112233); + block.push(0x44556677); + block.push(0x8899aabb); + block.push(0xccddeeff); + var plain = block; + + var key = []; + key.push(0x00010203); + key.push(0x04050607); + key.push(0x08090a0b); + key.push(0x0c0d0e0f); + key.push(0x10111213); + key.push(0x14151617); + key.push(0x18191a1b); + key.push(0x1c1d1e1f); + + var expect = []; + expect.push(0x8ea2b7ca); + expect.push(0x516745bf); + expect.push(0xeafc4990); + expect.push(0x4b496089); + + test.expect.html('8ea2b7ca516745bfeafc49904b496089'); + + var output = []; + var w = forge.aes._expandKey(key, false); + forge.aes._updateBlock(w, block, output, false); + + var out = forge.util.createBuffer(); + out.putInt32(output[0]); + out.putInt32(output[1]); + out.putInt32(output[2]); + out.putInt32(output[3]); + test.result.html(out.toHex()); + + test.check(); + }); + + addTest('aes-256 decrypt', function(task, test) + { + var block = []; + block.push(0x8ea2b7ca); + block.push(0x516745bf); + block.push(0xeafc4990); + block.push(0x4b496089); + + var key = []; + key.push(0x00010203); + key.push(0x04050607); + key.push(0x08090a0b); + key.push(0x0c0d0e0f); + key.push(0x10111213); + key.push(0x14151617); + key.push(0x18191a1b); + key.push(0x1c1d1e1f); + + var expect = []; + expect.push(0x00112233); + expect.push(0x44556677); + expect.push(0x8899aabb); + expect.push(0xccddeeff); + + test.expect.html('00112233445566778899aabbccddeeff'); + + var output = []; + w = forge.aes._expandKey(key, true); + forge.aes._updateBlock(w, block, output, true); + + var out = forge.util.createBuffer(); + out.putInt32(output[0]); + out.putInt32(output[1]); + out.putInt32(output[2]); + out.putInt32(output[3]); + test.result.html(out.toHex()); + + test.check(); + }); + + (function() + { + var keys = [ + '06a9214036b8a15b512e03d534120006', + 'c286696d887c9aa0611bbb3e2025a45a', + '6c3ea0477630ce21a2ce334aa746c2cd', + '56e47a38c5598974bc46903dba290349' + ]; + + var ivs = [ + '3dafba429d9eb430b422da802c9fac41', + '562e17996d093d28ddb3ba695a2e6f58', + 'c782dc4c098c66cbd9cd27d825682c81', + '8ce82eefbea0da3c44699ed7db51b7d9' + ]; + + var inputs = [ + 'Single block msg', + '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f', + 'This is a 48-byte message (exactly 3 AES blocks)', + 'a0a1a2a3a4a5a6a7a8a9aaabacadaeaf' + + 'b0b1b2b3b4b5b6b7b8b9babbbcbdbebf' + + 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf' + + 'd0d1d2d3d4d5d6d7d8d9dadbdcdddedf' + ]; + + var outputs = [ + 'e353779c1079aeb82708942dbe77181a', + 'd296cd94c2cccf8a3a863028b5e1dc0a7586602d253cfff91b8266bea6d61ab1', + 'd0a02b3836451753d493665d33f0e886' + + '2dea54cdb293abc7506939276772f8d5' + + '021c19216bad525c8579695d83ba2684', + 'c30e32ffedc0774e6aff6af0869f71aa' + + '0f3af07a9a31a9c684db207eb0ef8e4e' + + '35907aa632c3ffdf868bb7b29d3d46ad' + + '83ce9f9a102ee99d49a53e87f4c3da55' + ]; + + for(var i = 0; i < keys.length; ++i) + { + (function(i) + { + var key = forge.util.hexToBytes(keys[i]); + var iv = forge.util.hexToBytes(ivs[i]); + var input = (i & 1) ? forge.util.hexToBytes(inputs[i]) : inputs[i]; + var output = forge.util.hexToBytes(outputs[i]); + + addTest('aes-128 cbc encrypt', function(task, test) + { + // encrypt w/no padding + test.expect.html(outputs[i]); + var cipher = forge.aes.createEncryptionCipher(key); + cipher.start(iv); + cipher.update(forge.util.createBuffer(input)); + cipher.finish(function(){return true;}); + test.result.html(cipher.output.toHex()); + test.check(); + }); + + addTest('aes-128 cbc decrypt', function(task, test) + { + // decrypt w/no padding + test.expect.html(inputs[i]); + var cipher = forge.aes.createDecryptionCipher(key); + cipher.start(iv); + cipher.update(forge.util.createBuffer(output)); + cipher.finish(function(){return true;}); + var out = (i & 1) ? + cipher.output.toHex() : cipher.output.bytes(); + test.result.html(out); + test.check(); + }); + })(i); + } + })(); + + (function() + { + var keys = [ + '00000000000000000000000000000000', + '2b7e151628aed2a6abf7158809cf4f3c', + '2b7e151628aed2a6abf7158809cf4f3c', + '2b7e151628aed2a6abf7158809cf4f3c', + '2b7e151628aed2a6abf7158809cf4f3c', + '00000000000000000000000000000000' + ]; + + var ivs = [ + '80000000000000000000000000000000', + '000102030405060708090a0b0c0d0e0f', + '3B3FD92EB72DAD20333449F8E83CFB4A', + 'C8A64537A0B3A93FCDE3CDAD9F1CE58B', + '26751F67A3CBB140B1808CF187A4F4DF', + '60f9ff04fac1a25657bf5b36b5efaf75' + ]; + + var inputs = [ + '00000000000000000000000000000000', + '6bc1bee22e409f96e93d7e117393172a', + 'ae2d8a571e03ac9c9eb76fac45af8e51', + '30c81c46a35ce411e5fbc1191a0a52ef', + 'f69f2445df4f9b17ad2b417be66c3710', + 'This is a 48-byte message (exactly 3 AES blocks)' + ]; + + var outputs = [ + '3ad78e726c1ec02b7ebfe92b23d9ec34', + '3b3fd92eb72dad20333449f8e83cfb4a', + 'c8a64537a0b3a93fcde3cdad9f1ce58b', + '26751f67a3cbb140b1808cf187a4f4df', + 'c04b05357c5d1c0eeac4c66f9ff7f2e6', + '52396a2ba1ba420c5e5b699a814944d8' + + 'f4e7fbf984a038319fbc0b4ee45cfa6f' + + '07b2564beab5b5e92dbd44cb345f49b4' + ]; + + for(var i = 0; i < keys.length; ++i) + { + (function(i) + { + var key = forge.util.hexToBytes(keys[i]); + var iv = forge.util.hexToBytes(ivs[i]); + var input = (i !== 5) ? + forge.util.hexToBytes(inputs[i]) : inputs[i]; + var output = forge.util.hexToBytes(outputs[i]); + + addTest('aes-128 cfb encrypt', function(task, test) + { + // encrypt + test.expect.html(outputs[i]); + var cipher = forge.aes.createEncryptionCipher(key, 'CFB'); + cipher.start(iv); + cipher.update(forge.util.createBuffer(input)); + cipher.finish(); + test.result.html(cipher.output.toHex()); + test.check(); + }); + + addTest('aes-128 cfb decrypt', function(task, test) + { + // decrypt + test.expect.html(inputs[i]); + var cipher = forge.aes.createDecryptionCipher(key, 'CFB'); + cipher.start(iv); + cipher.update(forge.util.createBuffer(output)); + cipher.finish(); + var out = (i !== 5) ? + cipher.output.toHex() : cipher.output.getBytes(); + test.result.html(out); + test.check(); + }); + })(i); + } + })(); + + (function() + { + var keys = [ + '861009ec4d599fab1f40abc76e6f89880cff5833c79c548c99f9045f191cd90b' + ]; + + var ivs = [ + 'd927ad81199aa7dcadfdb4e47b6dc694' + ]; + + var inputs = [ + 'MY-DATA-AND-HERE-IS-MORE-DATA' + ]; + + var outputs = [ + '80eb666a9fc9e263faf71e87ffc94451d7d8df7cfcf2606470351dd5ac' + ]; + + for(var i = 0; i < keys.length; ++i) + { + (function(i) + { + var key = forge.util.hexToBytes(keys[i]); + var iv = forge.util.hexToBytes(ivs[i]); + var input = inputs[i]; + var output = forge.util.hexToBytes(outputs[i]); + + addTest('aes-256 cfb encrypt', function(task, test) + { + // encrypt + test.expect.html(outputs[i]); + var cipher = forge.aes.createEncryptionCipher(key, 'CFB'); + cipher.start(iv); + cipher.update(forge.util.createBuffer(input)); + cipher.finish(); + test.result.html(cipher.output.toHex()); + test.check(); + }); + + addTest('aes-256 cfb decrypt', function(task, test) + { + // decrypt + test.expect.html(inputs[i]); + var cipher = forge.aes.createDecryptionCipher(key, 'CFB'); + cipher.start(iv); + cipher.update(forge.util.createBuffer(output)); + cipher.finish(); + var out = cipher.output.getBytes(); + test.result.html(out); + test.check(); + }); + })(i); + } + })(); + + (function() + { + var keys = [ + '00000000000000000000000000000000', + '00000000000000000000000000000000' + ]; + + var ivs = [ + '80000000000000000000000000000000', + 'c8ca0d6a35dbeac776e911ee16bea7d3' + ]; + + var inputs = [ + '00000000000000000000000000000000', + 'This is a 48-byte message (exactly 3 AES blocks)' + ]; + + var outputs = [ + '3ad78e726c1ec02b7ebfe92b23d9ec34', + '39c0190727a76b2a90963426f63689cf' + + 'cdb8a2be8e20c5e877a81a724e3611f6' + + '2ecc386f2e941b2441c838906002be19' + ]; + + for(var i = 0; i < keys.length; ++i) + { + (function(i) + { + var key = forge.util.hexToBytes(keys[i]); + var iv = forge.util.hexToBytes(ivs[i]); + var input = (i !== 1) ? + forge.util.hexToBytes(inputs[i]) : inputs[i]; + var output = forge.util.hexToBytes(outputs[i]); + + addTest('aes-128 ofb encrypt', function(task, test) + { + // encrypt w/no padding + test.expect.html(outputs[i]); + var cipher = forge.aes.createEncryptionCipher(key, 'OFB'); + cipher.start(iv); + cipher.update(forge.util.createBuffer(input)); + cipher.finish(function(){return true;}); + test.result.html(cipher.output.toHex()); + test.check(); + }); + + addTest('aes-128 ofb decrypt', function(task, test) + { + // decrypt w/no padding + test.expect.html(inputs[i]); + var cipher = forge.aes.createDecryptionCipher(key, 'OFB'); + cipher.start(iv); + cipher.update(forge.util.createBuffer(output)); + cipher.finish(function(){return true;}); + var out = (i !== 1) ? + cipher.output.toHex() : cipher.output.getBytes(); + test.result.html(out); + test.check(); + }); + })(i); + } + })(); + + (function() + { + var keys = [ + '00000000000000000000000000000000', + '2b7e151628aed2a6abf7158809cf4f3c' + ]; + + var ivs = [ + '650cdb80ff9fc758342d2bd99ee2abcf', + 'f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff' + ]; + + var inputs = [ + 'This is a 48-byte message (exactly 3 AES blocks)', + '6bc1bee22e409f96e93d7e117393172a' + ]; + + var outputs = [ + '5ede11d00e9a76ec1d5e7e811ea3dd1c' + + 'e09ee941210f825d35718d3282796f1c' + + '07c3f1cb424f2b365766ab5229f5b5a4', + '874d6191b620e3261bef6864990db6ce' + ]; + + for(var i = 0; i < keys.length; ++i) + { + (function(i) + { + var key = forge.util.hexToBytes(keys[i]); + var iv = forge.util.hexToBytes(ivs[i]); + var input = (i !== 0) ? + forge.util.hexToBytes(inputs[i]) : inputs[i]; + var output = forge.util.hexToBytes(outputs[i]); + + addTest('aes-128 ctr encrypt', function(task, test) + { + // encrypt w/no padding + test.expect.html(outputs[i]); + var cipher = forge.aes.createEncryptionCipher(key, 'CTR'); + cipher.start(iv); + cipher.update(forge.util.createBuffer(input)); + cipher.finish(function(){return true;}); + test.result.html(cipher.output.toHex()); + test.check(); + }); + + addTest('aes-128 ctr decrypt', function(task, test) + { + // decrypt w/no padding + test.expect.html(inputs[i]); + var cipher = forge.aes.createDecryptionCipher(key, 'CTR'); + cipher.start(iv); + cipher.update(forge.util.createBuffer(output)); + cipher.finish(function(){return true;}); + var out = (i !== 0) ? + cipher.output.toHex() : cipher.output.getBytes(); + test.result.html(out); + test.check(); + }); + })(i); + } + })(); + + addTest('private key encryption', function(task, test) + { + var _privateKey = + '-----BEGIN RSA PRIVATE KEY-----\r\n' + + 'MIICXQIBAAKBgQDL0EugUiNGMWscLAVM0VoMdhDZEJOqdsUMpx9U0YZI7szokJqQ\r\n' + + 'NIwokiQ6EonNnWSMlIvy46AhnlRYn+ezeTeU7eMGTkP3VF29vXBo+dLq5e+8VyAy\r\n' + + 'Q3FzM1wI4ts4hRACF8w6mqygXQ7i/SDu8/rXqRGtvnM+z0MYDdKo80efzwIDAQAB\r\n' + + 'AoGAIzkGONi5G+JifmXlLJdplom486p3upf4Ce2/7mqfaG9MnkyPSairKD/JXvfh\r\n' + + 'NNWkkN8DKKDKBcVVElPgORYT0qwrWc7ueLBMUCbRXb1ZyfEulimG0R3kjUh7NYau\r\n' + + 'DaIkVgfykXGSQMZx8FoaT6L080zd+0emKDDYRrb+/kgJNJECQQDoUZoiC2K/DWNY\r\n' + + 'h3/ppZ0ane2y4SBmJUHJVMPQ2CEgxsrJTxet668ckNCKaOP/3VFPoWC41f17DvKq\r\n' + + 'noYINNntAkEA4JbZBZBVUrQFhHlrpXT4jzqtO2RlKZzEq8qmFZfEErxOT1WMyyCi\r\n' + + 'lAQ5gUKardo1Kf0omC8Xq/uO9ZYdED55KwJBALs6cJ65UFaq4oLJiQPzLd7yokuE\r\n' + + 'dcj8g71PLBTW6jPxIiMFNA89nz3FU9wIVp+xbMNhSoMMKqIPVPC+m0Rn260CQQDA\r\n' + + 'I83fWK/mZWUjBM33a68KumRiH238v8XyQxj7+C8i6D8G2GXvkigFAehAkb7LZZd+\r\n' + + 'KLuGFyPlWv3fVWHf99KpAkBQFKk3MRMl6IGJZUEFQe4l5whm8LkGU4acSqv9B3xt\r\n' + + 'qROkCrsFrMPqjuuzEmyHoQZ64r2PLJg7FOuyhBnQUOt4\r\n' + + '-----END RSA PRIVATE KEY-----'; + var pk = forge.pki.privateKeyFromPem(_privateKey); + var pem1 = forge.pki.privateKeyToPem(pk); + var pem2 = forge.pki.encryptRsaPrivateKey( + pk, 'password', {'encAlg': 'aes128'}); + var privateKey = forge.pki.decryptRsaPrivateKey(pem2, 'password'); + var pem3 = forge.pki.privateKeyToPem(privateKey); + if(pem1 === pem3) + { + test.pass(); + } + else + { + test.fail(); + } + }); + + addTest('random', function(task, test) + { + forge.random.getBytes(16); + forge.random.getBytes(24); + forge.random.getBytes(32); + + var b = forge.random.getBytes(10); + test.result.html(forge.util.bytesToHex(b)); + if(b.length === 10) + { + test.pass(); + } + else + { + test.fail(); + } + }); + + addTest('asn.1 oid => der', function(task, test) + { + test.expect.html('2a864886f70d'); + test.result.html(forge.asn1.oidToDer('1.2.840.113549').toHex()); + test.check(); + }); + + addTest('asn.1 der => oid', function(task, test) + { + var der = '2a864886f70d'; + test.expect.html('1.2.840.113549'); + test.result.html(forge.asn1.derToOid(forge.util.hexToBytes(der))); + test.check(); + }); + + (function() + { + var _privateKey = + '-----BEGIN RSA PRIVATE KEY-----\r\n' + + 'MIICXQIBAAKBgQDL0EugUiNGMWscLAVM0VoMdhDZEJOqdsUMpx9U0YZI7szokJqQ\r\n' + + 'NIwokiQ6EonNnWSMlIvy46AhnlRYn+ezeTeU7eMGTkP3VF29vXBo+dLq5e+8VyAy\r\n' + + 'Q3FzM1wI4ts4hRACF8w6mqygXQ7i/SDu8/rXqRGtvnM+z0MYDdKo80efzwIDAQAB\r\n' + + 'AoGAIzkGONi5G+JifmXlLJdplom486p3upf4Ce2/7mqfaG9MnkyPSairKD/JXvfh\r\n' + + 'NNWkkN8DKKDKBcVVElPgORYT0qwrWc7ueLBMUCbRXb1ZyfEulimG0R3kjUh7NYau\r\n' + + 'DaIkVgfykXGSQMZx8FoaT6L080zd+0emKDDYRrb+/kgJNJECQQDoUZoiC2K/DWNY\r\n' + + 'h3/ppZ0ane2y4SBmJUHJVMPQ2CEgxsrJTxet668ckNCKaOP/3VFPoWC41f17DvKq\r\n' + + 'noYINNntAkEA4JbZBZBVUrQFhHlrpXT4jzqtO2RlKZzEq8qmFZfEErxOT1WMyyCi\r\n' + + 'lAQ5gUKardo1Kf0omC8Xq/uO9ZYdED55KwJBALs6cJ65UFaq4oLJiQPzLd7yokuE\r\n' + + 'dcj8g71PLBTW6jPxIiMFNA89nz3FU9wIVp+xbMNhSoMMKqIPVPC+m0Rn260CQQDA\r\n' + + 'I83fWK/mZWUjBM33a68KumRiH238v8XyQxj7+C8i6D8G2GXvkigFAehAkb7LZZd+\r\n' + + 'KLuGFyPlWv3fVWHf99KpAkBQFKk3MRMl6IGJZUEFQe4l5whm8LkGU4acSqv9B3xt\r\n' + + 'qROkCrsFrMPqjuuzEmyHoQZ64r2PLJg7FOuyhBnQUOt4\r\n' + + '-----END RSA PRIVATE KEY-----\r\n'; + + var _publicKey = + '-----BEGIN PUBLIC KEY-----\r\n' + + 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDL0EugUiNGMWscLAVM0VoMdhDZ\r\n' + + 'EJOqdsUMpx9U0YZI7szokJqQNIwokiQ6EonNnWSMlIvy46AhnlRYn+ezeTeU7eMG\r\n' + + 'TkP3VF29vXBo+dLq5e+8VyAyQ3FzM1wI4ts4hRACF8w6mqygXQ7i/SDu8/rXqRGt\r\n' + + 'vnM+z0MYDdKo80efzwIDAQAB\r\n' + + '-----END PUBLIC KEY-----\r\n'; + + var _certificate = + '-----BEGIN CERTIFICATE-----\r\n' + + 'MIIDIjCCAougAwIBAgIJANE2aHSbwpaRMA0GCSqGSIb3DQEBBQUAMGoxCzAJBgNV\r\n' + + 'BAYTAlVTMREwDwYDVQQIEwhWaXJnaW5pYTETMBEGA1UEBxMKQmxhY2tzYnVyZzEN\r\n' + + 'MAsGA1UEChMEVGVzdDENMAsGA1UECxMEVGVzdDEVMBMGA1UEAxMMbXlzZXJ2ZXIu\r\n' + + 'Y29tMB4XDTEwMDYxOTE3MzYyOFoXDTExMDYxOTE3MzYyOFowajELMAkGA1UEBhMC\r\n' + + 'VVMxETAPBgNVBAgTCFZpcmdpbmlhMRMwEQYDVQQHEwpCbGFja3NidXJnMQ0wCwYD\r\n' + + 'VQQKEwRUZXN0MQ0wCwYDVQQLEwRUZXN0MRUwEwYDVQQDEwxteXNlcnZlci5jb20w\r\n' + + 'gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMvQS6BSI0YxaxwsBUzRWgx2ENkQ\r\n' + + 'k6p2xQynH1TRhkjuzOiQmpA0jCiSJDoSic2dZIyUi/LjoCGeVFif57N5N5Tt4wZO\r\n' + + 'Q/dUXb29cGj50url77xXIDJDcXMzXAji2ziFEAIXzDqarKBdDuL9IO7z+tepEa2+\r\n' + + 'cz7PQxgN0qjzR5/PAgMBAAGjgc8wgcwwHQYDVR0OBBYEFPV1Y+DHXW6bA/r9sv1y\r\n' + + 'NJ8jAwMAMIGcBgNVHSMEgZQwgZGAFPV1Y+DHXW6bA/r9sv1yNJ8jAwMAoW6kbDBq\r\n' + + 'MQswCQYDVQQGEwJVUzERMA8GA1UECBMIVmlyZ2luaWExEzARBgNVBAcTCkJsYWNr\r\n' + + 'c2J1cmcxDTALBgNVBAoTBFRlc3QxDTALBgNVBAsTBFRlc3QxFTATBgNVBAMTDG15\r\n' + + 'c2VydmVyLmNvbYIJANE2aHSbwpaRMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEF\r\n' + + 'BQADgYEARdH2KOlJWTC1CS2y/PAvg4uiM31PXMC1hqSdJlnLM1MY4hRfuf9VyTeX\r\n' + + 'Y6FdybcyDLSxKn9id+g9229ci9/s9PI+QmD5vXd8yZyScLc2JkYB4GC6+9D1+/+x\r\n' + + 's2hzMxuK6kzZlP+0l9LGcraMQPGRydjCARZZm4Uegln9rh85XFQ=\r\n' + + '-----END CERTIFICATE-----\r\n'; + + var _signature = + '9200ece65cdaed36bcc20b94c65af852e4f88f0b4fe5b249d54665f815992ac4' + + '3a1399e65d938c6a7f16dd39d971a53ca66523209dbbfbcb67afa579dbb0c220' + + '672813d9e6f4818f29b9becbb29da2032c5e422da97e0c39bfb7a2e7d568615a' + + '5073af0337ff215a8e1b2332d668691f4fb731440055420c24ac451dd3c913f4'; + + addTest('private key from pem/to pem', function(task, test) + { + try + { + // convert from pem + var key = forge.pki.privateKeyFromPem(_privateKey); + //forge.log.debug(cat, 'privateKey', key); + + // convert back to pem + var pem = forge.pki.privateKeyToPem(key); + test.expect.html(_privateKey); + test.result.html(pem); + test.check(); + } + catch(ex) + { + forge.log.error('test', ex); + test.fail(); + } + }); + + addTest('public key from pem/to pem', function(task, test) + { + try + { + // convert from pem + var key = forge.pki.publicKeyFromPem(_publicKey); + //forge.log.debug(cat, 'publicKey', key); + + // convert back to pem + var pem = forge.pki.publicKeyToPem(key); + test.expect.html(_publicKey); + test.result.html(pem); + test.check(); + } + catch(ex) + { + forge.log.error('test', ex); + test.fail(); + } + }); + + addTest('certificate key from pem/to pem', function(task, test) + { + try + { + var cert = forge.pki.certificateFromPem(_certificate); + /* + forge.log.debug(cat, 'cert', cert); + forge.log.debug(cat, 'CN', cert.subject.getField('CN').value); + forge.log.debug(cat, 'C', + cert.subject.getField({shortName: 'C'}).value); + forge.log.debug(cat, 'stateOrProvinceName', + cert.subject.getField({name: 'stateOrProvinceName'}).value); + forge.log.debug(cat, '2.5.4.7', + cert.subject.getField({type: '2.5.4.7'}).value); + */ + // convert back to pem + var pem = forge.pki.certificateToPem(cert); + test.expect.html(_certificate); + test.result.html(pem); + test.check(); + } + catch(ex) + { + forge.log.error('test', ex); + test.fail(); + } + }); + + addTest('verify signature', function(task, test) + { + try + { + var key = forge.pki.publicKeyFromPem(_publicKey); + var md = forge.md.sha1.create(); + md.update('0123456789abcdef'); + var signature = forge.util.hexToBytes(_signature); + var success = key.verify(md.digest().getBytes(), signature); + if(success) + { + test.pass(); + } + else + { + test.fail(); + } + } + catch(ex) + { + forge.log.error('test', ex); + test.fail(); + } + }); + + addTest('sign and verify', function(task, test) + { + try + { + var privateKey = forge.pki.privateKeyFromPem(_privateKey); + var publicKey = forge.pki.publicKeyFromPem(_publicKey); + + // do sign + var md = forge.md.sha1.create(); + md.update('0123456789abcdef'); + var st = +new Date(); + var signature = privateKey.sign(md); + var et = +new Date(); + //forge.log.debug(cat, 'sign time', (et - st) + 'ms'); + + // do verify + st = +new Date(); + var success = publicKey.verify(md.digest().getBytes(), signature); + et = +new Date(); + //forge.log.debug(cat, 'verify time', (et - st) + 'ms'); + if(success) + { + test.pass(); + } + else + { + test.fail(); + } + } + catch(ex) + { + forge.log.error('test', ex); + test.fail(); + } + }); + + addTest('certificate verify', function(task, test) + { + try + { + var cert = forge.pki.certificateFromPem(_certificate, true); + //forge.log.debug(cat, 'cert', cert); + var success = cert.verify(cert); + if(success) + { + test.pass(); + } + else + { + test.fail(); + } + } + catch(ex) + { + forge.log.error('test', ex); + test.fail(); + } + }); + })(); + + addTest('TLS prf', function(task, test) + { + // Note: This test vector is originally from: + // http://www.imc.org/ietf-tls/mail-archive/msg01589.html + // But that link is now dead. + var secret = forge.util.createBuffer(); + for(var i = 0; i < 48; ++i) + { + secret.putByte(0xAB); + } + secret = secret.getBytes(); + var seed = forge.util.createBuffer(); + for(var i = 0; i < 64; ++i) + { + seed.putByte(0xCD); + } + seed = seed.getBytes(); + + var bytes = forge.tls.prf_tls1(secret, 'PRF Testvector', seed, 104); + var expect = + 'd3d4d1e349b5d515044666d51de32bab258cb521' + + 'b6b053463e354832fd976754443bcf9a296519bc' + + '289abcbc1187e4ebd31e602353776c408aafb74c' + + 'bc85eff69255f9788faa184cbb957a9819d84a5d' + + '7eb006eb459d3ae8de9810454b8b2d8f1afbc655' + + 'a8c9a013'; + test.expect.html(expect); + test.result.html(bytes.toHex()); + test.check(); + }); + + // function to create certificate + var createCert = function(keys, cn, data) + { + var cert = forge.pki.createCertificate(); + cert.serialNumber = '01'; + cert.validity.notBefore = new Date(); + cert.validity.notAfter = new Date(); + cert.validity.notAfter.setFullYear( + cert.validity.notBefore.getFullYear() + 1); + var attrs = [{ + name: 'commonName', + value: cn + }, { + name: 'countryName', + value: 'US' + }, { + shortName: 'ST', + value: 'Virginia' + }, { + name: 'localityName', + value: 'Blacksburg' + }, { + name: 'organizationName', + value: 'Test' + }, { + shortName: 'OU', + value: 'Test' + }]; + cert.setSubject(attrs); + cert.setIssuer(attrs); + cert.setExtensions([{ + name: 'basicConstraints', + cA: true + }, { + name: 'keyUsage', + keyCertSign: true, + digitalSignature: true, + nonRepudiation: true, + keyEncipherment: true, + dataEncipherment: true + }, { + name: 'subjectAltName', + altNames: [{ + type: 6, // URI + value: 'http://myuri.com/webid#me' + }] + }]); + // FIXME: add subjectKeyIdentifier extension + // FIXME: add authorityKeyIdentifier extension + cert.publicKey = keys.publicKey; + + // self-sign certificate + cert.sign(keys.privateKey); + + // save data + data[cn] = { + cert: forge.pki.certificateToPem(cert), + privateKey: forge.pki.privateKeyToPem(keys.privateKey) + }; + }; + + var generateCert = function(task, test, cn, data) + { + task.block(); + + // create key-generation state and function to step algorithm + test.result.html( + 'Generating 512-bit key-pair and certificate for \"' + cn + '\".'); + var state = forge.pki.rsa.createKeyPairGenerationState(512); + var kgTime = +new Date(); + var step = function() + { + // step key-generation + if(!forge.pki.rsa.stepKeyPairGenerationState(state, 1000)) + { + test.result.html(test.result.html() + '.'); + setTimeout(step, 1); + } + // key-generation complete + else + { + kgTime = +new Date() - kgTime; + forge.log.debug(cat, 'Total key-gen time', kgTime + 'ms'); + try + { + createCert(state.keys, cn, data); + test.result.html( + test.result.html() + 'done. Time=' + kgTime + 'ms. '); + task.unblock(); + } + catch(ex) + { + forge.log.error(cat, ex, ex.message ? ex.message : ''); + test.result.html(ex.message); + test.fail(); + task.fail(); + } + } + }; + + // run key-gen algorithm + setTimeout(step, 0); + }; + + var clientSessionCache1 = forge.tls.createSessionCache(); + var serverSessionCache1 = forge.tls.createSessionCache(); + addTest('TLS connection, w/o client-certificate', function(task, test) + { + var data = {}; + + task.next('generate server certifcate', function(task) + { + generateCert(task, test, 'server', data); + }); + + task.next('starttls', function(task) + { + test.result.html(test.result.html() + 'Starting TLS...'); + + var end = + { + client: null, + server: null + }; + var success = false; + + // create client + end.client = forge.tls.createConnection( + { + server: false, + caStore: [data.server.cert], + sessionCache: clientSessionCache1, + // optional cipher suites in order of preference + cipherSuites: [ + forge.tls.CipherSuites.TLS_RSA_WITH_AES_128_CBC_SHA, + forge.tls.CipherSuites.TLS_RSA_WITH_AES_256_CBC_SHA], + virtualHost: 'server', + verify: function(c, verified, depth, certs) + { + test.result.html(test.result.html() + + 'Client verifying certificate w/CN: \"' + + certs[0].subject.getField('CN').value + + '\", verified: ' + verified + '...'); + if(verified !== true) + { + test.fail(); + task.fail(); + } + return verified; + }, + connected: function(c) + { + test.result.html(test.result.html() + 'Client connected...'); + + // send message to server + setTimeout(function() + { + c.prepare('Hello Server'); + }, 1); + }, + tlsDataReady: function(c) + { + // send TLS data to server + end.server.process(c.tlsData.getBytes()); + }, + dataReady: function(c) + { + var response = c.data.getBytes(); + test.result.html(test.result.html() + + 'Client received \"' + response + '\"'); + success = (response === 'Hello Client'); + c.close(); + }, + closed: function(c) + { + test.result.html(test.result.html() + 'Client disconnected.'); + test.result.html(success ? 'Success' : 'Failure'); + if(success) + { + test.expect.html('Success'); + task.unblock(); + test.pass(); + } + else + { + console.log('closed fail'); + test.fail(); + task.fail(); + } + }, + error: function(c, error) + { + test.result.html(test.result.html() + 'Error: ' + error.message); + test.fail(); + task.fail(); + } + }); + + // create server + end.server = forge.tls.createConnection( + { + server: true, + sessionCache: serverSessionCache1, + // optional cipher suites in order of preference + cipherSuites: [ + forge.tls.CipherSuites.TLS_RSA_WITH_AES_128_CBC_SHA, + forge.tls.CipherSuites.TLS_RSA_WITH_AES_256_CBC_SHA], + connected: function(c) + { + test.result.html(test.result.html() + 'Server connected...'); + }, + getCertificate: function(c, hint) + { + test.result.html(test.result.html() + + 'Server getting certificate for \"' + hint[0] + '\"...'); + return data.server.cert; + }, + getPrivateKey: function(c, cert) + { + return data.server.privateKey; + }, + tlsDataReady: function(c) + { + // send TLS data to client + end.client.process(c.tlsData.getBytes()); + }, + dataReady: function(c) + { + test.result.html(test.result.html() + + 'Server received \"' + c.data.getBytes() + '\"'); + + // send response + c.prepare('Hello Client'); + c.close(); + }, + closed: function(c) + { + test.result.html(test.result.html() + 'Server disconnected.'); + }, + error: function(c, error) + { + test.result.html(test.result.html() + 'Error: ' + error.message); + test.fail(); + task.fail(); + } + }); + + // start handshake + task.block(); + end.client.handshake(); + }); + }); + + var clientSessionCache2 = forge.tls.createSessionCache(); + var serverSessionCache2 = forge.tls.createSessionCache(); + addTest('TLS connection, w/optional client-certificate', function(task, test) + { + var data = {}; + + task.next('generate server certifcate', function(task) + { + generateCert(task, test, 'server', data); + }); + + // client-cert generated but not sent in this test + task.next('generate client certifcate', function(task) + { + generateCert(task, test, 'client', data); + }); + + task.next('starttls', function(task) + { + test.result.html(test.result.html() + 'Starting TLS...'); + + var end = + { + client: null, + server: null + }; + var success = false; + + // create client + end.client = forge.tls.createConnection( + { + server: false, + caStore: [data.server.cert], + sessionCache: clientSessionCache2, + // supported cipher suites in order of preference + cipherSuites: [ + forge.tls.CipherSuites.TLS_RSA_WITH_AES_128_CBC_SHA, + forge.tls.CipherSuites.TLS_RSA_WITH_AES_256_CBC_SHA], + virtualHost: 'server', + verify: function(c, verified, depth, certs) + { + test.result.html(test.result.html() + + 'Client verifying certificate w/CN: \"' + + certs[0].subject.getField('CN').value + + '\", verified: ' + verified + '...'); + if(verified !== true) + { + test.fail(); + task.fail(); + } + return verified; + }, + connected: function(c) + { + test.result.html(test.result.html() + 'Client connected...'); + + // send message to server + setTimeout(function() + { + c.prepare('Hello Server'); + }, 1); + }, + tlsDataReady: function(c) + { + // send TLS data to server + end.server.process(c.tlsData.getBytes()); + }, + dataReady: function(c) + { + var response = c.data.getBytes(); + test.result.html(test.result.html() + + 'Client received \"' + response + '\"'); + success = (response === 'Hello Client'); + c.close(); + }, + closed: function(c) + { + test.result.html(test.result.html() + 'Client disconnected.'); + test.result.html(success ? 'Success' : 'Failure'); + if(success) + { + test.expect.html('Success'); + task.unblock(); + test.pass(); + } + else + { + console.log('closed fail'); + test.fail(); + task.fail(); + } + }, + error: function(c, error) + { + test.result.html(test.result.html() + 'Error: ' + error.message); + test.fail(); + task.fail(); + } + }); + + // create server + end.server = forge.tls.createConnection( + { + server: true, + caStore: [data.client.cert], + sessionCache: serverSessionCache2, + // supported cipher suites in order of preference + cipherSuites: [ + forge.tls.CipherSuites.TLS_RSA_WITH_AES_128_CBC_SHA, + forge.tls.CipherSuites.TLS_RSA_WITH_AES_256_CBC_SHA], + connected: function(c) + { + test.result.html(test.result.html() + 'Server connected...'); + }, + verifyClient: 'optional', + verify: function(c, verified, depth, certs) + { + test.result.html(test.result.html() + + 'Server verifying certificate w/CN: \"' + + certs[0].subject.getField('CN').value + + '\", verified: ' + verified + '...'); + if(verified !== true) + { + test.fail(); + task.fail(); + } + return verified; + }, + getCertificate: function(c, hint) + { + test.result.html(test.result.html() + + 'Server getting certificate for \"' + hint[0] + '\"...'); + return data.server.cert; + }, + getPrivateKey: function(c, cert) + { + return data.server.privateKey; + }, + tlsDataReady: function(c) + { + // send TLS data to client + end.client.process(c.tlsData.getBytes()); + }, + dataReady: function(c) + { + test.result.html(test.result.html() + + 'Server received \"' + c.data.getBytes() + '\"'); + + // send response + c.prepare('Hello Client'); + c.close(); + }, + closed: function(c) + { + test.result.html(test.result.html() + 'Server disconnected.'); + }, + error: function(c, error) + { + test.result.html(test.result.html() + 'Error: ' + error.message); + test.fail(); + task.fail(); + } + }); + + // start handshake + task.block(); + end.client.handshake(); + }); + }); + + var clientSessionCache3 = forge.tls.createSessionCache(); + var serverSessionCache3 = forge.tls.createSessionCache(); + addTest('TLS connection, w/client-certificate', function(task, test) + { + var data = {}; + + task.next('generate server certifcate', function(task) + { + generateCert(task, test, 'server', data); + }); + + task.next('generate client certifcate', function(task) + { + generateCert(task, test, 'client', data); + }); + + task.next('starttls', function(task) + { + test.result.html(test.result.html() + 'Starting TLS...'); + + var end = + { + client: null, + server: null + }; + var success = false; + + // create client + end.client = forge.tls.createConnection( + { + server: false, + caStore: [data.server.cert], + sessionCache: clientSessionCache3, + // supported cipher suites in order of preference + cipherSuites: [ + forge.tls.CipherSuites.TLS_RSA_WITH_AES_128_CBC_SHA, + forge.tls.CipherSuites.TLS_RSA_WITH_AES_256_CBC_SHA], + virtualHost: 'server', + verify: function(c, verified, depth, certs) + { + test.result.html(test.result.html() + + 'Client verifying certificate w/CN: \"' + + certs[0].subject.getField('CN').value + + '\", verified: ' + verified + '...'); + if(verified !== true) + { + test.fail(); + task.fail(); + } + return verified; + }, + connected: function(c) + { + test.result.html(test.result.html() + 'Client connected...'); + + // send message to server + setTimeout(function() + { + c.prepare('Hello Server'); + }, 1); + }, + getCertificate: function(c, hint) + { + test.result.html(test.result.html() + + 'Client getting certificate ...'); + return data.client.cert; + }, + getPrivateKey: function(c, cert) + { + return data.client.privateKey; + }, + tlsDataReady: function(c) + { + // send TLS data to server + end.server.process(c.tlsData.getBytes()); + }, + dataReady: function(c) + { + var response = c.data.getBytes(); + test.result.html(test.result.html() + + 'Client received \"' + response + '\"'); + success = (response === 'Hello Client'); + c.close(); + }, + closed: function(c) + { + test.result.html(test.result.html() + 'Client disconnected.'); + test.result.html(success ? 'Success' : 'Failure'); + if(success) + { + test.expect.html('Success'); + task.unblock(); + test.pass(); + } + else + { + console.log('closed fail'); + test.fail(); + task.fail(); + } + }, + error: function(c, error) + { + test.result.html(test.result.html() + 'Error: ' + error.message); + test.fail(); + task.fail(); + } + }); + + // create server + end.server = forge.tls.createConnection( + { + server: true, + caStore: [data.client.cert], + sessionCache: serverSessionCache3, + // supported cipher suites in order of preference + cipherSuites: [ + forge.tls.CipherSuites.TLS_RSA_WITH_AES_128_CBC_SHA, + forge.tls.CipherSuites.TLS_RSA_WITH_AES_256_CBC_SHA], + connected: function(c) + { + test.result.html(test.result.html() + 'Server connected...'); + }, + verifyClient: true, // use 'optional' to request but not require + verify: function(c, verified, depth, certs) + { + test.result.html(test.result.html() + + 'Server verifying certificate w/CN: \"' + + certs[0].subject.getField('CN').value + + '\", verified: ' + verified + '...'); + if(verified !== true) + { + test.fail(); + task.fail(); + } + return verified; + }, + getCertificate: function(c, hint) + { + test.result.html(test.result.html() + + 'Server getting certificate for \"' + hint[0] + '\"...'); + return data.server.cert; + }, + getPrivateKey: function(c, cert) + { + return data.server.privateKey; + }, + tlsDataReady: function(c) + { + // send TLS data to client + end.client.process(c.tlsData.getBytes()); + }, + dataReady: function(c) + { + test.result.html(test.result.html() + + 'Server received \"' + c.data.getBytes() + '\"'); + + // send response + c.prepare('Hello Client'); + c.close(); + }, + closed: function(c) + { + test.result.html(test.result.html() + 'Server disconnected.'); + }, + error: function(c, error) + { + test.result.html(test.result.html() + 'Error: ' + error.message); + test.fail(); + task.fail(); + } + }); + + // start handshake + task.block(); + end.client.handshake(); + }); + }); + + init(); +}); diff --git a/school/node_modules/node-forge/tests/favicon.ico b/school/node_modules/node-forge/tests/favicon.ico new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/school/node_modules/node-forge/tests/favicon.ico diff --git a/school/node_modules/node-forge/tests/flash/Test.as b/school/node_modules/node-forge/tests/flash/Test.as new file mode 100644 index 0000000..7c03727 --- /dev/null +++ b/school/node_modules/node-forge/tests/flash/Test.as @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2010 Digital Bazaar, Inc. All rights reserved. + * + * @author Dave Longley + */ +package +{ + import flash.display.Sprite; + + public class Test extends Sprite + { + import flash.events.*; + import flash.net.*; + + import flash.external.ExternalInterface; + import flash.system.Security; + + public function Test() + { + try + { + // FIXME: replace 'localhost' with cross-domain host to hit + var xhost:String = "localhost"; + Security.loadPolicyFile("xmlsocket://" + xhost + ":80"); + + var loader:URLLoader = new URLLoader(); + loader.addEventListener( + Event.COMPLETE, completeHandler); + loader.addEventListener( + Event.OPEN, openHandler); + loader.addEventListener( + ProgressEvent.PROGRESS, progressHandler); + loader.addEventListener( + SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler); + loader.addEventListener( + HTTPStatusEvent.HTTP_STATUS, httpStatusHandler); + loader.addEventListener( + IOErrorEvent.IO_ERROR, ioErrorHandler); + + var request:URLRequest = new URLRequest( + "http://" + xhost + "/index.html"); + loader.load(request); + } + catch(e:Error) + { + log("error=" + e.errorID + "," + e.name + "," + e.message); + throw e; + } + } + + private function log(obj:Object):void + { + if(obj is String) + { + var str:String = obj as String; + ExternalInterface.call("console.log", "Test", str); + } + else if(obj is Error) + { + var e:Error = obj as Error; + log("error=" + e.errorID + "," + e.name + "," + e.message); + } + } + + private function completeHandler(event:Event):void + { + var loader:URLLoader = URLLoader(event.target); + log("complete: " + loader.data); + } + + private function openHandler(event:Event):void + { + log("open: " + event); + } + + private function progressHandler(event:ProgressEvent):void + { + log("progress:" + event.bytesLoaded + " total: " + event.bytesTotal); + } + + private function securityErrorHandler(event:SecurityErrorEvent):void + { + log("securityError: " + event); + } + + private function httpStatusHandler(event:HTTPStatusEvent):void + { + log("httpStatus: " + event); + } + + private function ioErrorHandler(event:IOErrorEvent):void + { + log("ioError: " + event); + } + } +} diff --git a/school/node_modules/node-forge/tests/flash/build-flash.xml b/school/node_modules/node-forge/tests/flash/build-flash.xml new file mode 100644 index 0000000..f037c58 --- /dev/null +++ b/school/node_modules/node-forge/tests/flash/build-flash.xml @@ -0,0 +1,7 @@ +<flex-config> + <compiler> + <source-path> + <path-element>.</path-element> + </source-path> + </compiler> +</flex-config> diff --git a/school/node_modules/node-forge/tests/flash/index.html b/school/node_modules/node-forge/tests/flash/index.html new file mode 100644 index 0000000..26a10b8 --- /dev/null +++ b/school/node_modules/node-forge/tests/flash/index.html @@ -0,0 +1,27 @@ +<html> + <head> + <link type="text/css" rel="stylesheet" media="all" href="screen.css" /> + <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js"></script> + + <script type="text/javascript"> + //<![CDATA[ + swfobject.embedSWF( + 'Test.swf', 'test', '0', '0', '9.0.0', + false, {}, {allowscriptaccess: 'always'}, {}); + //]]> + </script> + </head> + <body> + <div class="header"> + <h1>Flash Cross-Domain URLLoader Test</h1> + </div> + + <div class="content"> + + <div id="test"> + <p>Could not load the flash test.</p> + </div> + + </div> + </body> +</html> diff --git a/school/node_modules/node-forge/tests/forge_ssl/forge/__init__.py b/school/node_modules/node-forge/tests/forge_ssl/forge/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/school/node_modules/node-forge/tests/forge_ssl/forge/__init__.py diff --git a/school/node_modules/node-forge/tests/forge_ssl/forge/_ssl.c b/school/node_modules/node-forge/tests/forge_ssl/forge/_ssl.c new file mode 100644 index 0000000..bdef8c9 --- /dev/null +++ b/school/node_modules/node-forge/tests/forge_ssl/forge/_ssl.c @@ -0,0 +1,1770 @@ +/* SSL socket module + + SSL support based on patches by Brian E Gallew and Laszlo Kovacs. + Re-worked a bit by Bill Janssen to add server-side support and + certificate decoding. Chris Stawarz contributed some non-blocking + patches. + + This module is imported by ssl.py. It should *not* be used + directly. + + XXX should partial writes be enabled, SSL_MODE_ENABLE_PARTIAL_WRITE? + + XXX integrate several "shutdown modes" as suggested in + http://bugs.python.org/issue8108#msg102867 ? +*/ + +#include "Python.h" + +#ifdef WITH_THREAD +#include "pythread.h" +#define PySSL_BEGIN_ALLOW_THREADS { \ + PyThreadState *_save = NULL; \ + if (_ssl_locks_count>0) {_save = PyEval_SaveThread();} +#define PySSL_BLOCK_THREADS if (_ssl_locks_count>0){PyEval_RestoreThread(_save)}; +#define PySSL_UNBLOCK_THREADS if (_ssl_locks_count>0){_save = PyEval_SaveThread()}; +#define PySSL_END_ALLOW_THREADS if (_ssl_locks_count>0){PyEval_RestoreThread(_save);} \ + } + +#else /* no WITH_THREAD */ + +#define PySSL_BEGIN_ALLOW_THREADS +#define PySSL_BLOCK_THREADS +#define PySSL_UNBLOCK_THREADS +#define PySSL_END_ALLOW_THREADS + +#endif + +enum py_ssl_error { + /* these mirror ssl.h */ + PY_SSL_ERROR_NONE, + PY_SSL_ERROR_SSL, + PY_SSL_ERROR_WANT_READ, + PY_SSL_ERROR_WANT_WRITE, + PY_SSL_ERROR_WANT_X509_LOOKUP, + PY_SSL_ERROR_SYSCALL, /* look at error stack/return value/errno */ + PY_SSL_ERROR_ZERO_RETURN, + PY_SSL_ERROR_WANT_CONNECT, + /* start of non ssl.h errorcodes */ + PY_SSL_ERROR_EOF, /* special case of SSL_ERROR_SYSCALL */ + PY_SSL_ERROR_INVALID_ERROR_CODE +}; + +enum py_ssl_server_or_client { + PY_SSL_CLIENT, + PY_SSL_SERVER +}; + +enum py_ssl_cert_requirements { + PY_SSL_CERT_NONE, + PY_SSL_CERT_OPTIONAL, + PY_SSL_CERT_REQUIRED +}; + +enum py_ssl_version { + PY_SSL_VERSION_SSL2, + PY_SSL_VERSION_SSL3, + PY_SSL_VERSION_SSL23, + PY_SSL_VERSION_TLS1 +}; + +enum py_ssl_sess_cache_mode { + PY_SSL_SESS_CACHE_OFF, + PY_SSL_SESS_CACHE_CLIENT, + PY_SSL_SESS_CACHE_SERVER, + PY_SSL_SESS_CACHE_BOTH +}; + +/* Include symbols from _socket module */ +#include "socketmodule.h" + +#if defined(HAVE_POLL_H) +#include <poll.h> +#elif defined(HAVE_SYS_POLL_H) +#include <sys/poll.h> +#endif + +/* Include OpenSSL header files */ +#include "openssl/rsa.h" +#include "openssl/crypto.h" +#include "openssl/x509.h" +#include "openssl/x509v3.h" +#include "openssl/pem.h" +#include "openssl/ssl.h" +#include "openssl/err.h" +#include "openssl/rand.h" + +/* SSL error object */ +static PyObject *PySSLErrorObject; + +#ifdef WITH_THREAD + +/* serves as a flag to see whether we've initialized the SSL thread support. */ +/* 0 means no, greater than 0 means yes */ + +static unsigned int _ssl_locks_count = 0; + +#endif /* def WITH_THREAD */ + +/* SSL socket object */ + +#define X509_NAME_MAXLEN 256 + +/* RAND_* APIs got added to OpenSSL in 0.9.5 */ +#if OPENSSL_VERSION_NUMBER >= 0x0090500fL +# define HAVE_OPENSSL_RAND 1 +#else +# undef HAVE_OPENSSL_RAND +#endif + +typedef struct { + PyObject_HEAD + PySocketSockObject *Socket; /* Socket on which we're layered */ + int inherited; + SSL_CTX* ctx; + SSL* ssl; + X509* peer_cert; + char server[X509_NAME_MAXLEN]; + char issuer[X509_NAME_MAXLEN]; + int shutdown_seen_zero; + +} PySSLObject; + +static PyTypeObject PySSL_Type; +static PyObject *PySSL_SSLwrite(PySSLObject *self, PyObject *args); +static PyObject *PySSL_SSLread(PySSLObject *self, PyObject *args); +static int check_socket_and_wait_for_timeout(PySocketSockObject *s, + int writing); +static PyObject *PySSL_peercert(PySSLObject *self, PyObject *args); +static PyObject *PySSL_cipher(PySSLObject *self); + +#define PySSLObject_Check(v) (Py_TYPE(v) == &PySSL_Type) + +typedef enum { + SOCKET_IS_NONBLOCKING, + SOCKET_IS_BLOCKING, + SOCKET_HAS_TIMED_OUT, + SOCKET_HAS_BEEN_CLOSED, + SOCKET_TOO_LARGE_FOR_SELECT, + SOCKET_OPERATION_OK +} timeout_state; + +/* Wrap error strings with filename and line # */ +#define STRINGIFY1(x) #x +#define STRINGIFY2(x) STRINGIFY1(x) +#define ERRSTR1(x,y,z) (x ":" y ": " z) +#define ERRSTR(x) ERRSTR1("_ssl.c", STRINGIFY2(__LINE__), x) + +/* XXX It might be helpful to augment the error message generated + below with the name of the SSL function that generated the error. + I expect it's obvious most of the time. +*/ + +static PyObject * +PySSL_SetError(PySSLObject *obj, int ret, char *filename, int lineno) +{ + PyObject *v; + char buf[2048]; + char *errstr; + int err; + enum py_ssl_error p = PY_SSL_ERROR_NONE; + + assert(ret <= 0); + + if (obj->ssl != NULL) { + err = SSL_get_error(obj->ssl, ret); + + switch (err) { + case SSL_ERROR_ZERO_RETURN: + errstr = "TLS/SSL connection has been closed"; + p = PY_SSL_ERROR_ZERO_RETURN; + break; + case SSL_ERROR_WANT_READ: + errstr = "The operation did not complete (read)"; + p = PY_SSL_ERROR_WANT_READ; + break; + case SSL_ERROR_WANT_WRITE: + p = PY_SSL_ERROR_WANT_WRITE; + errstr = "The operation did not complete (write)"; + break; + case SSL_ERROR_WANT_X509_LOOKUP: + p = PY_SSL_ERROR_WANT_X509_LOOKUP; + errstr = "The operation did not complete (X509 lookup)"; + break; + case SSL_ERROR_WANT_CONNECT: + p = PY_SSL_ERROR_WANT_CONNECT; + errstr = "The operation did not complete (connect)"; + break; + case SSL_ERROR_SYSCALL: + { + unsigned long e = ERR_get_error(); + if (e == 0) { + if (ret == 0 || !obj->Socket) { + p = PY_SSL_ERROR_EOF; + errstr = "EOF occurred in violation of protocol"; + } else if (ret == -1) { + /* underlying BIO reported an I/O error */ + ERR_clear_error(); + return obj->Socket->errorhandler(); + } else { /* possible? */ + p = PY_SSL_ERROR_SYSCALL; + errstr = "Some I/O error occurred"; + } + } else { + p = PY_SSL_ERROR_SYSCALL; + /* XXX Protected by global interpreter lock */ + errstr = ERR_error_string(e, NULL); + } + break; + } + case SSL_ERROR_SSL: + { + unsigned long e = ERR_get_error(); + p = PY_SSL_ERROR_SSL; + if (e != 0) + /* XXX Protected by global interpreter lock */ + errstr = ERR_error_string(e, NULL); + else { /* possible? */ + errstr = "A failure in the SSL library occurred"; + } + break; + } + default: + p = PY_SSL_ERROR_INVALID_ERROR_CODE; + errstr = "Invalid error code"; + } + } else { + errstr = ERR_error_string(ERR_peek_last_error(), NULL); + } + PyOS_snprintf(buf, sizeof(buf), "_ssl.c:%d: %s", lineno, errstr); + ERR_clear_error(); + v = Py_BuildValue("(is)", p, buf); + if (v != NULL) { + PyErr_SetObject(PySSLErrorObject, v); + Py_DECREF(v); + } + return NULL; +} + +static PyObject * +_setSSLError (char *errstr, int errcode, char *filename, int lineno) { + + char buf[2048]; + PyObject *v; + + if (errstr == NULL) { + errcode = ERR_peek_last_error(); + errstr = ERR_error_string(errcode, NULL); + } + PyOS_snprintf(buf, sizeof(buf), "_ssl.c:%d: %s", lineno, errstr); + ERR_clear_error(); + v = Py_BuildValue("(is)", errcode, buf); + if (v != NULL) { + PyErr_SetObject(PySSLErrorObject, v); + Py_DECREF(v); + } + return NULL; +} + +static PySSLObject * +newPySSLObject(PySSLObject *ssl_object, PySocketSockObject *Sock, + char *key_file, char *cert_file, + enum py_ssl_server_or_client socket_type, + enum py_ssl_cert_requirements certreq, + enum py_ssl_version proto_version, + enum py_ssl_sess_cache_mode cache_mode, + char *sess_id_ctx, + char *cacerts_file) +{ + PySSLObject *self; + char *errstr = NULL; + int ret; + int verification_mode; + int sess_cache_mode; + + self = PyObject_New(PySSLObject, &PySSL_Type); /* Create new object */ + if (self == NULL) + return NULL; + memset(self->server, '\0', sizeof(char) * X509_NAME_MAXLEN); + memset(self->issuer, '\0', sizeof(char) * X509_NAME_MAXLEN); + self->peer_cert = NULL; + self->inherited = 0; + self->ssl = NULL; + self->ctx = NULL; + self->Socket = NULL; + + /* Make sure the SSL error state is initialized */ + (void) ERR_get_state(); + ERR_clear_error(); + + if ((key_file && !cert_file) || (!key_file && cert_file)) { + errstr = ERRSTR("Both the key & certificate files " + "must be specified"); + goto fail; + } + + if ((socket_type == PY_SSL_SERVER) && (ssl_object == NULL) && + ((key_file == NULL) || (cert_file == NULL))) { + errstr = ERRSTR("Both the key & certificate files " + "must be specified for server-side operation"); + goto fail; + } + + if (ssl_object != NULL) { + self->inherited = 1; + self->ctx = ssl_object->ctx; + } else { + self->inherited = 0; + + PySSL_BEGIN_ALLOW_THREADS + if (proto_version == PY_SSL_VERSION_TLS1) + self->ctx = SSL_CTX_new(TLSv1_method()); /* Set up context */ + else if (proto_version == PY_SSL_VERSION_SSL3) + self->ctx = SSL_CTX_new(SSLv3_method()); /* Set up context */ + else if (proto_version == PY_SSL_VERSION_SSL2) + self->ctx = SSL_CTX_new(SSLv2_method()); /* Set up context */ + else if (proto_version == PY_SSL_VERSION_SSL23) + self->ctx = SSL_CTX_new(SSLv23_method()); /* Set up context */ + PySSL_END_ALLOW_THREADS + } + + if (self->ctx == NULL) { + errstr = ERRSTR("Invalid SSL protocol variant specified."); + goto fail; + } + + if (self->inherited == 0 && certreq != PY_SSL_CERT_NONE) { + if (cacerts_file == NULL) { + errstr = ERRSTR("No root certificates specified for " + "verification of other-side certificates."); + goto fail; + } else { + PySSL_BEGIN_ALLOW_THREADS + ret = SSL_CTX_load_verify_locations(self->ctx, + cacerts_file, + NULL); + PySSL_END_ALLOW_THREADS + if (ret != 1) { + _setSSLError(NULL, 0, __FILE__, __LINE__); + goto fail; + } + } + } + if (self->inherited == 0 && key_file) { + PySSL_BEGIN_ALLOW_THREADS + ret = SSL_CTX_use_PrivateKey_file(self->ctx, key_file, + SSL_FILETYPE_PEM); + PySSL_END_ALLOW_THREADS + if (ret != 1) { + _setSSLError(NULL, ret, __FILE__, __LINE__); + goto fail; + } + + PySSL_BEGIN_ALLOW_THREADS + ret = SSL_CTX_use_certificate_chain_file(self->ctx, + cert_file); + PySSL_END_ALLOW_THREADS + if (ret != 1) { + /* + fprintf(stderr, "ret is %d, errcode is %lu, %lu, with file \"%s\"\n", + ret, ERR_peek_error(), ERR_peek_last_error(), cert_file); + */ + if (ERR_peek_last_error() != 0) { + _setSSLError(NULL, ret, __FILE__, __LINE__); + goto fail; + } + } + } + + if (self->inherited == 0) { + /* ssl compatibility */ + SSL_CTX_set_options(self->ctx, SSL_OP_ALL); + + /* session cache mode */ + PySSL_BEGIN_ALLOW_THREADS + sess_cache_mode = SSL_SESS_CACHE_SERVER; + if (cache_mode == PY_SSL_SESS_CACHE_OFF) + sess_cache_mode = SSL_SESS_CACHE_OFF; + else if (cache_mode == PY_SSL_SESS_CACHE_CLIENT) + sess_cache_mode = SSL_SESS_CACHE_CLIENT; + else if (cache_mode == PY_SSL_SESS_CACHE_SERVER) + sess_cache_mode = SSL_SESS_CACHE_SERVER; + else if (cache_mode == PY_SSL_SESS_CACHE_BOTH) + sess_cache_mode = SSL_SESS_CACHE_BOTH; + SSL_CTX_set_session_cache_mode(self->ctx, sess_cache_mode); + + /* session id context */ + if (sess_id_ctx != NULL) + SSL_CTX_set_session_id_context(self->ctx, + (const unsigned char*)sess_id_ctx, + strlen(sess_id_ctx)); + PySSL_END_ALLOW_THREADS + + verification_mode = SSL_VERIFY_NONE; + if (certreq == PY_SSL_CERT_OPTIONAL) + verification_mode = SSL_VERIFY_PEER; + else if (certreq == PY_SSL_CERT_REQUIRED) + verification_mode = (SSL_VERIFY_PEER | + SSL_VERIFY_FAIL_IF_NO_PEER_CERT); + SSL_CTX_set_verify(self->ctx, verification_mode, + NULL); /* set verify lvl */ + } + + self->ssl = SSL_new(self->ctx); /* New ssl struct */ + SSL_set_fd(self->ssl, Sock->sock_fd); /* Set the socket for SSL */ +#ifdef SSL_MODE_AUTO_RETRY + SSL_set_mode(self->ssl, SSL_MODE_AUTO_RETRY); +#endif + + /* If the socket is in non-blocking mode or timeout mode, set the BIO + * to non-blocking mode (blocking is the default) + */ + if (Sock->sock_timeout >= 0.0) { + /* Set both the read and write BIO's to non-blocking mode */ + BIO_set_nbio(SSL_get_rbio(self->ssl), 1); + BIO_set_nbio(SSL_get_wbio(self->ssl), 1); + } + + PySSL_BEGIN_ALLOW_THREADS + if (socket_type == PY_SSL_CLIENT) + SSL_set_connect_state(self->ssl); + else + SSL_set_accept_state(self->ssl); + PySSL_END_ALLOW_THREADS + + self->Socket = Sock; + Py_INCREF(self->Socket); + return self; + fail: + if (errstr) + PyErr_SetString(PySSLErrorObject, errstr); + Py_DECREF(self); + return NULL; +} + +static PyObject * +PySSL_sslwrap(PyObject *self, PyObject *args) +{ + PySocketSockObject *Sock; + int server_side = 0; + int verification_mode = PY_SSL_CERT_NONE; + int protocol = PY_SSL_VERSION_SSL23; + int sess_cache_mode = PY_SSL_SESS_CACHE_SERVER; + char *sess_id_ctx = NULL; + char *key_file = NULL; + char *cert_file = NULL; + char *cacerts_file = NULL; + + if (!PyArg_ParseTuple(args, "O!i|zziiizz:sslwrap", + PySocketModule.Sock_Type, + &Sock, + &server_side, + &key_file, &cert_file, + &verification_mode, &protocol, + &sess_cache_mode, &sess_id_ctx, + &cacerts_file)) + return NULL; + + /* + fprintf(stderr, + "server_side is %d, keyfile %p, certfile %p, verify_mode %d, " + "protocol %d, sess_cache_mode %d, sess_id_ctx %p, certs %p\n", + server_side, key_file, cert_file, verification_mode, + protocol, sess_cache_mode, sess_id_ctx, cacerts_file); + */ + + return (PyObject *) newPySSLObject(NULL, Sock, key_file, cert_file, + server_side, verification_mode, + protocol, sess_cache_mode, sess_id_ctx, + cacerts_file); +} + +PyDoc_STRVAR(sslwrap_doc, +"sslwrap(socket, server_side, [keyfile, certfile, certs_mode, protocol,\n" +" sess_cache_mode, sess_id_ctx, cacertsfile]) -> sslobject"); + +/* SSL object methods */ + +static PyObject * +PySSL_SSLwrap_accepted(PySSLObject *self, PyObject *args) +{ + PySocketSockObject *Sock; + + if (!PyArg_ParseTuple(args, "O!:sslwrap", + PySocketModule.Sock_Type, + &Sock)) + return NULL; + + return (PyObject *) newPySSLObject(self, Sock, NULL, NULL, + PY_SSL_SERVER, 0, 0, 0, NULL, NULL); +} + +PyDoc_STRVAR(PySSL_SSLwrap_accepted_doc, +"wrap_accepted(socket) -> sslobject"); + +static PyObject *PySSL_SSLdo_handshake(PySSLObject *self) +{ + int ret; + int err; + int sockstate, nonblocking; + + /* just in case the blocking state of the socket has been changed */ + nonblocking = (self->Socket->sock_timeout >= 0.0); + BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking); + BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking); + + /* Actually negotiate SSL connection */ + /* XXX If SSL_do_handshake() returns 0, it's also a failure. */ + sockstate = 0; + do { + PySSL_BEGIN_ALLOW_THREADS + ret = SSL_do_handshake(self->ssl); + err = SSL_get_error(self->ssl, ret); + PySSL_END_ALLOW_THREADS + if(PyErr_CheckSignals()) { + return NULL; + } + if (err == SSL_ERROR_WANT_READ) { + sockstate = check_socket_and_wait_for_timeout(self->Socket, 0); + } else if (err == SSL_ERROR_WANT_WRITE) { + sockstate = check_socket_and_wait_for_timeout(self->Socket, 1); + } else { + sockstate = SOCKET_OPERATION_OK; + } + if (sockstate == SOCKET_HAS_TIMED_OUT) { + PyErr_SetString(PySSLErrorObject, + ERRSTR("The handshake operation timed out")); + return NULL; + } else if (sockstate == SOCKET_HAS_BEEN_CLOSED) { + PyErr_SetString(PySSLErrorObject, + ERRSTR("Underlying socket has been closed.")); + return NULL; + } else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) { + PyErr_SetString(PySSLErrorObject, + ERRSTR("Underlying socket too large for select().")); + return NULL; + } else if (sockstate == SOCKET_IS_NONBLOCKING) { + break; + } + } while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE); + if (ret < 1) + return PySSL_SetError(self, ret, __FILE__, __LINE__); + + if (self->peer_cert) + X509_free (self->peer_cert); + PySSL_BEGIN_ALLOW_THREADS + if ((self->peer_cert = SSL_get_peer_certificate(self->ssl))) { + X509_NAME_oneline(X509_get_subject_name(self->peer_cert), + self->server, X509_NAME_MAXLEN); + X509_NAME_oneline(X509_get_issuer_name(self->peer_cert), + self->issuer, X509_NAME_MAXLEN); + } + PySSL_END_ALLOW_THREADS + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +PySSL_server(PySSLObject *self) +{ + return PyString_FromString(self->server); +} + +static PyObject * +PySSL_issuer(PySSLObject *self) +{ + return PyString_FromString(self->issuer); +} + +static PyObject * +_create_tuple_for_attribute (ASN1_OBJECT *name, ASN1_STRING *value) { + + char namebuf[X509_NAME_MAXLEN]; + int buflen; + PyObject *name_obj; + PyObject *value_obj; + PyObject *attr; + unsigned char *valuebuf = NULL; + + buflen = OBJ_obj2txt(namebuf, sizeof(namebuf), name, 0); + if (buflen < 0) { + _setSSLError(NULL, 0, __FILE__, __LINE__); + goto fail; + } + name_obj = PyString_FromStringAndSize(namebuf, buflen); + if (name_obj == NULL) + goto fail; + + buflen = ASN1_STRING_to_UTF8(&valuebuf, value); + if (buflen < 0) { + _setSSLError(NULL, 0, __FILE__, __LINE__); + Py_DECREF(name_obj); + goto fail; + } + value_obj = PyUnicode_DecodeUTF8((char *) valuebuf, + buflen, "strict"); + OPENSSL_free(valuebuf); + if (value_obj == NULL) { + Py_DECREF(name_obj); + goto fail; + } + attr = PyTuple_New(2); + if (attr == NULL) { + Py_DECREF(name_obj); + Py_DECREF(value_obj); + goto fail; + } + PyTuple_SET_ITEM(attr, 0, name_obj); + PyTuple_SET_ITEM(attr, 1, value_obj); + return attr; + + fail: + return NULL; +} + +static PyObject * +_create_tuple_for_X509_NAME (X509_NAME *xname) +{ + PyObject *dn = NULL; /* tuple which represents the "distinguished name" */ + PyObject *rdn = NULL; /* tuple to hold a "relative distinguished name" */ + PyObject *rdnt; + PyObject *attr = NULL; /* tuple to hold an attribute */ + int entry_count = X509_NAME_entry_count(xname); + X509_NAME_ENTRY *entry; + ASN1_OBJECT *name; + ASN1_STRING *value; + int index_counter; + int rdn_level = -1; + int retcode; + + dn = PyList_New(0); + if (dn == NULL) + return NULL; + /* now create another tuple to hold the top-level RDN */ + rdn = PyList_New(0); + if (rdn == NULL) + goto fail0; + + for (index_counter = 0; + index_counter < entry_count; + index_counter++) + { + entry = X509_NAME_get_entry(xname, index_counter); + + /* check to see if we've gotten to a new RDN */ + if (rdn_level >= 0) { + if (rdn_level != entry->set) { + /* yes, new RDN */ + /* add old RDN to DN */ + rdnt = PyList_AsTuple(rdn); + Py_DECREF(rdn); + if (rdnt == NULL) + goto fail0; + retcode = PyList_Append(dn, rdnt); + Py_DECREF(rdnt); + if (retcode < 0) + goto fail0; + /* create new RDN */ + rdn = PyList_New(0); + if (rdn == NULL) + goto fail0; + } + } + rdn_level = entry->set; + + /* now add this attribute to the current RDN */ + name = X509_NAME_ENTRY_get_object(entry); + value = X509_NAME_ENTRY_get_data(entry); + attr = _create_tuple_for_attribute(name, value); + /* + fprintf(stderr, "RDN level %d, attribute %s: %s\n", + entry->set, + PyString_AS_STRING(PyTuple_GET_ITEM(attr, 0)), + PyString_AS_STRING(PyTuple_GET_ITEM(attr, 1))); + */ + if (attr == NULL) + goto fail1; + retcode = PyList_Append(rdn, attr); + Py_DECREF(attr); + if (retcode < 0) + goto fail1; + } + /* now, there's typically a dangling RDN */ + if ((rdn != NULL) && (PyList_Size(rdn) > 0)) { + rdnt = PyList_AsTuple(rdn); + Py_DECREF(rdn); + if (rdnt == NULL) + goto fail0; + retcode = PyList_Append(dn, rdnt); + Py_DECREF(rdnt); + if (retcode < 0) + goto fail0; + } + + /* convert list to tuple */ + rdnt = PyList_AsTuple(dn); + Py_DECREF(dn); + if (rdnt == NULL) + return NULL; + return rdnt; + + fail1: + Py_XDECREF(rdn); + + fail0: + Py_XDECREF(dn); + return NULL; +} + +static PyObject * +_get_peer_alt_names (X509 *certificate) { + + /* this code follows the procedure outlined in + OpenSSL's crypto/x509v3/v3_prn.c:X509v3_EXT_print() + function to extract the STACK_OF(GENERAL_NAME), + then iterates through the stack to add the + names. */ + + int i, j; + PyObject *peer_alt_names = Py_None; + PyObject *v, *t; + X509_EXTENSION *ext = NULL; + GENERAL_NAMES *names = NULL; + GENERAL_NAME *name; + X509V3_EXT_METHOD *method; + BIO *biobuf = NULL; + char buf[2048]; + char *vptr; + int len; + const unsigned char *p; + + if (certificate == NULL) + return peer_alt_names; + + /* get a memory buffer */ + biobuf = BIO_new(BIO_s_mem()); + + i = 0; + while ((i = X509_get_ext_by_NID( + certificate, NID_subject_alt_name, i)) >= 0) { + + if (peer_alt_names == Py_None) { + peer_alt_names = PyList_New(0); + if (peer_alt_names == NULL) + goto fail; + } + + /* now decode the altName */ + ext = X509_get_ext(certificate, i); + if(!(method = X509V3_EXT_get(ext))) { + PyErr_SetString(PySSLErrorObject, + ERRSTR("No method for internalizing subjectAltName!")); + goto fail; + } + + p = ext->value->data; + if (method->it) + names = (GENERAL_NAMES*) (ASN1_item_d2i(NULL, + &p, + ext->value->length, + ASN1_ITEM_ptr(method->it))); + else + names = (GENERAL_NAMES*) (method->d2i(NULL, + &p, + ext->value->length)); + + for(j = 0; j < sk_GENERAL_NAME_num(names); j++) { + + /* get a rendering of each name in the set of names */ + + name = sk_GENERAL_NAME_value(names, j); + if (name->type == GEN_DIRNAME) { + + /* we special-case DirName as a tuple of tuples of attributes */ + + t = PyTuple_New(2); + if (t == NULL) { + goto fail; + } + + v = PyString_FromString("DirName"); + if (v == NULL) { + Py_DECREF(t); + goto fail; + } + PyTuple_SET_ITEM(t, 0, v); + + v = _create_tuple_for_X509_NAME (name->d.dirn); + if (v == NULL) { + Py_DECREF(t); + goto fail; + } + PyTuple_SET_ITEM(t, 1, v); + + } else { + + /* for everything else, we use the OpenSSL print form */ + + (void) BIO_reset(biobuf); + GENERAL_NAME_print(biobuf, name); + len = BIO_gets(biobuf, buf, sizeof(buf)-1); + if (len < 0) { + _setSSLError(NULL, 0, __FILE__, __LINE__); + goto fail; + } + vptr = strchr(buf, ':'); + if (vptr == NULL) + goto fail; + t = PyTuple_New(2); + if (t == NULL) + goto fail; + v = PyString_FromStringAndSize(buf, (vptr - buf)); + if (v == NULL) { + Py_DECREF(t); + goto fail; + } + PyTuple_SET_ITEM(t, 0, v); + v = PyString_FromStringAndSize((vptr + 1), (len - (vptr - buf + 1))); + if (v == NULL) { + Py_DECREF(t); + goto fail; + } + PyTuple_SET_ITEM(t, 1, v); + } + + /* and add that rendering to the list */ + + if (PyList_Append(peer_alt_names, t) < 0) { + Py_DECREF(t); + goto fail; + } + Py_DECREF(t); + } + } + BIO_free(biobuf); + if (peer_alt_names != Py_None) { + v = PyList_AsTuple(peer_alt_names); + Py_DECREF(peer_alt_names); + return v; + } else { + return peer_alt_names; + } + + + fail: + if (biobuf != NULL) + BIO_free(biobuf); + + if (peer_alt_names != Py_None) { + Py_XDECREF(peer_alt_names); + } + + return NULL; +} + +static PyObject * +_decode_certificate (X509 *certificate, int verbose) { + + PyObject *retval = NULL; + BIO *biobuf = NULL; + PyObject *peer; + PyObject *peer_alt_names = NULL; + PyObject *issuer; + PyObject *version; + PyObject *sn_obj; + ASN1_INTEGER *serialNumber; + char buf[2048]; + int len; + ASN1_TIME *notBefore, *notAfter; + PyObject *pnotBefore, *pnotAfter; + + retval = PyDict_New(); + if (retval == NULL) + return NULL; + + peer = _create_tuple_for_X509_NAME( + X509_get_subject_name(certificate)); + if (peer == NULL) + goto fail0; + if (PyDict_SetItemString(retval, (const char *) "subject", peer) < 0) { + Py_DECREF(peer); + goto fail0; + } + Py_DECREF(peer); + + if (verbose) { + issuer = _create_tuple_for_X509_NAME( + X509_get_issuer_name(certificate)); + if (issuer == NULL) + goto fail0; + if (PyDict_SetItemString(retval, (const char *)"issuer", issuer) < 0) { + Py_DECREF(issuer); + goto fail0; + } + Py_DECREF(issuer); + + version = PyInt_FromLong(X509_get_version(certificate) + 1); + if (PyDict_SetItemString(retval, "version", version) < 0) { + Py_DECREF(version); + goto fail0; + } + Py_DECREF(version); + } + + /* get a memory buffer */ + biobuf = BIO_new(BIO_s_mem()); + + if (verbose) { + + (void) BIO_reset(biobuf); + serialNumber = X509_get_serialNumber(certificate); + /* should not exceed 20 octets, 160 bits, so buf is big enough */ + i2a_ASN1_INTEGER(biobuf, serialNumber); + len = BIO_gets(biobuf, buf, sizeof(buf)-1); + if (len < 0) { + _setSSLError(NULL, 0, __FILE__, __LINE__); + goto fail1; + } + sn_obj = PyString_FromStringAndSize(buf, len); + if (sn_obj == NULL) + goto fail1; + if (PyDict_SetItemString(retval, "serialNumber", sn_obj) < 0) { + Py_DECREF(sn_obj); + goto fail1; + } + Py_DECREF(sn_obj); + + (void) BIO_reset(biobuf); + notBefore = X509_get_notBefore(certificate); + ASN1_TIME_print(biobuf, notBefore); + len = BIO_gets(biobuf, buf, sizeof(buf)-1); + if (len < 0) { + _setSSLError(NULL, 0, __FILE__, __LINE__); + goto fail1; + } + pnotBefore = PyString_FromStringAndSize(buf, len); + if (pnotBefore == NULL) + goto fail1; + if (PyDict_SetItemString(retval, "notBefore", pnotBefore) < 0) { + Py_DECREF(pnotBefore); + goto fail1; + } + Py_DECREF(pnotBefore); + } + + (void) BIO_reset(biobuf); + notAfter = X509_get_notAfter(certificate); + ASN1_TIME_print(biobuf, notAfter); + len = BIO_gets(biobuf, buf, sizeof(buf)-1); + if (len < 0) { + _setSSLError(NULL, 0, __FILE__, __LINE__); + goto fail1; + } + pnotAfter = PyString_FromStringAndSize(buf, len); + if (pnotAfter == NULL) + goto fail1; + if (PyDict_SetItemString(retval, "notAfter", pnotAfter) < 0) { + Py_DECREF(pnotAfter); + goto fail1; + } + Py_DECREF(pnotAfter); + + /* Now look for subjectAltName */ + + peer_alt_names = _get_peer_alt_names(certificate); + if (peer_alt_names == NULL) + goto fail1; + else if (peer_alt_names != Py_None) { + if (PyDict_SetItemString(retval, "subjectAltName", + peer_alt_names) < 0) { + Py_DECREF(peer_alt_names); + goto fail1; + } + Py_DECREF(peer_alt_names); + } + + BIO_free(biobuf); + return retval; + + fail1: + if (biobuf != NULL) + BIO_free(biobuf); + fail0: + Py_XDECREF(retval); + return NULL; +} + + +static PyObject * +PySSL_test_decode_certificate (PyObject *mod, PyObject *args) { + + PyObject *retval = NULL; + char *filename = NULL; + X509 *x=NULL; + BIO *cert; + int verbose = 1; + + if (!PyArg_ParseTuple(args, "s|i:test_decode_certificate", &filename, &verbose)) + return NULL; + + if ((cert=BIO_new(BIO_s_file())) == NULL) { + PyErr_SetString(PySSLErrorObject, "Can't malloc memory to read file"); + goto fail0; + } + + if (BIO_read_filename(cert,filename) <= 0) { + PyErr_SetString(PySSLErrorObject, "Can't open file"); + goto fail0; + } + + x = PEM_read_bio_X509_AUX(cert,NULL, NULL, NULL); + if (x == NULL) { + PyErr_SetString(PySSLErrorObject, "Error decoding PEM-encoded file"); + goto fail0; + } + + retval = _decode_certificate(x, verbose); + + fail0: + + if (cert != NULL) BIO_free(cert); + return retval; +} + + +static PyObject * +PySSL_peercert(PySSLObject *self, PyObject *args) +{ + PyObject *retval = NULL; + int len; + int verification; + PyObject *binary_mode = Py_None; + + if (!PyArg_ParseTuple(args, "|O:peer_certificate", &binary_mode)) + return NULL; + + if (!self->peer_cert) + Py_RETURN_NONE; + + if (PyObject_IsTrue(binary_mode)) { + /* return cert in DER-encoded format */ + + unsigned char *bytes_buf = NULL; + + bytes_buf = NULL; + len = i2d_X509(self->peer_cert, &bytes_buf); + if (len < 0) { + PySSL_SetError(self, len, __FILE__, __LINE__); + return NULL; + } + retval = PyString_FromStringAndSize((const char *) bytes_buf, len); + OPENSSL_free(bytes_buf); + return retval; + + } else { + + verification = SSL_CTX_get_verify_mode(self->ctx); + if ((verification & SSL_VERIFY_PEER) == 0) + return PyDict_New(); + else + return _decode_certificate (self->peer_cert, 0); + } +} + +PyDoc_STRVAR(PySSL_peercert_doc, +"peer_certificate([der=False]) -> certificate\n\ +\n\ +Returns the certificate for the peer. If no certificate was provided,\n\ +returns None. If a certificate was provided, but not validated, returns\n\ +an empty dictionary. Otherwise returns a dict containing information\n\ +about the peer certificate.\n\ +\n\ +If the optional argument is True, returns a DER-encoded copy of the\n\ +peer certificate, or None if no certificate was provided. This will\n\ +return the certificate even if it wasn't validated."); + +static PyObject *PySSL_cipher (PySSLObject *self) { + + PyObject *retval, *v; + SSL_CIPHER *current; + char *cipher_name; + char *cipher_protocol; + + if (self->ssl == NULL) + return Py_None; + current = SSL_get_current_cipher(self->ssl); + if (current == NULL) + return Py_None; + + retval = PyTuple_New(3); + if (retval == NULL) + return NULL; + + cipher_name = (char *) SSL_CIPHER_get_name(current); + if (cipher_name == NULL) { + PyTuple_SET_ITEM(retval, 0, Py_None); + } else { + v = PyString_FromString(cipher_name); + if (v == NULL) + goto fail0; + PyTuple_SET_ITEM(retval, 0, v); + } + cipher_protocol = SSL_CIPHER_get_version(current); + if (cipher_protocol == NULL) { + PyTuple_SET_ITEM(retval, 1, Py_None); + } else { + v = PyString_FromString(cipher_protocol); + if (v == NULL) + goto fail0; + PyTuple_SET_ITEM(retval, 1, v); + } + v = PyInt_FromLong(SSL_CIPHER_get_bits(current, NULL)); + if (v == NULL) + goto fail0; + PyTuple_SET_ITEM(retval, 2, v); + return retval; + + fail0: + Py_DECREF(retval); + return NULL; +} + +static void PySSL_dealloc(PySSLObject *self) +{ + if (self->peer_cert) /* Possible not to have one? */ + X509_free (self->peer_cert); + if (self->ssl) + SSL_free(self->ssl); + if (self->ctx && self->inherited == 0) + SSL_CTX_free(self->ctx); + Py_XDECREF(self->Socket); + PyObject_Del(self); +} + +/* If the socket has a timeout, do a select()/poll() on the socket. + The argument writing indicates the direction. + Returns one of the possibilities in the timeout_state enum (above). + */ + +static int +check_socket_and_wait_for_timeout(PySocketSockObject *s, int writing) +{ + fd_set fds; + struct timeval tv; + int rc; + + /* Nothing to do unless we're in timeout mode (not non-blocking) */ + if (s->sock_timeout < 0.0) + return SOCKET_IS_BLOCKING; + else if (s->sock_timeout == 0.0) + return SOCKET_IS_NONBLOCKING; + + /* Guard against closed socket */ + if (s->sock_fd < 0) + return SOCKET_HAS_BEEN_CLOSED; + + /* Prefer poll, if available, since you can poll() any fd + * which can't be done with select(). */ +#ifdef HAVE_POLL + { + struct pollfd pollfd; + int timeout; + + pollfd.fd = s->sock_fd; + pollfd.events = writing ? POLLOUT : POLLIN; + + /* s->sock_timeout is in seconds, timeout in ms */ + timeout = (int)(s->sock_timeout * 1000 + 0.5); + PySSL_BEGIN_ALLOW_THREADS + rc = poll(&pollfd, 1, timeout); + PySSL_END_ALLOW_THREADS + + goto normal_return; + } +#endif + + /* Guard against socket too large for select*/ +#ifndef Py_SOCKET_FD_CAN_BE_GE_FD_SETSIZE + if (s->sock_fd >= FD_SETSIZE) + return SOCKET_TOO_LARGE_FOR_SELECT; +#endif + + /* Construct the arguments to select */ + tv.tv_sec = (int)s->sock_timeout; + tv.tv_usec = (int)((s->sock_timeout - tv.tv_sec) * 1e6); + FD_ZERO(&fds); + FD_SET(s->sock_fd, &fds); + + /* See if the socket is ready */ + PySSL_BEGIN_ALLOW_THREADS + if (writing) + rc = select(s->sock_fd+1, NULL, &fds, NULL, &tv); + else + rc = select(s->sock_fd+1, &fds, NULL, NULL, &tv); + PySSL_END_ALLOW_THREADS + +#ifdef HAVE_POLL +normal_return: +#endif + /* Return SOCKET_TIMED_OUT on timeout, SOCKET_OPERATION_OK otherwise + (when we are able to write or when there's something to read) */ + return rc == 0 ? SOCKET_HAS_TIMED_OUT : SOCKET_OPERATION_OK; +} + +static PyObject *PySSL_SSLwrite(PySSLObject *self, PyObject *args) +{ + char *data; + int len; + int count; + int sockstate; + int err; + int nonblocking; + + if (!PyArg_ParseTuple(args, "s#:write", &data, &count)) + return NULL; + + /* just in case the blocking state of the socket has been changed */ + nonblocking = (self->Socket->sock_timeout >= 0.0); + BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking); + BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking); + + sockstate = check_socket_and_wait_for_timeout(self->Socket, 1); + if (sockstate == SOCKET_HAS_TIMED_OUT) { + PyErr_SetString(PySSLErrorObject, + "The write operation timed out"); + return NULL; + } else if (sockstate == SOCKET_HAS_BEEN_CLOSED) { + PyErr_SetString(PySSLErrorObject, + "Underlying socket has been closed."); + return NULL; + } else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) { + PyErr_SetString(PySSLErrorObject, + "Underlying socket too large for select()."); + return NULL; + } + do { + err = 0; + PySSL_BEGIN_ALLOW_THREADS + len = SSL_write(self->ssl, data, count); + err = SSL_get_error(self->ssl, len); + PySSL_END_ALLOW_THREADS + if(PyErr_CheckSignals()) { + return NULL; + } + if (err == SSL_ERROR_WANT_READ) { + sockstate = check_socket_and_wait_for_timeout(self->Socket, 0); + } else if (err == SSL_ERROR_WANT_WRITE) { + sockstate = check_socket_and_wait_for_timeout(self->Socket, 1); + } else { + sockstate = SOCKET_OPERATION_OK; + } + if (sockstate == SOCKET_HAS_TIMED_OUT) { + PyErr_SetString(PySSLErrorObject, + "The write operation timed out"); + return NULL; + } else if (sockstate == SOCKET_HAS_BEEN_CLOSED) { + PyErr_SetString(PySSLErrorObject, + "Underlying socket has been closed."); + return NULL; + } else if (sockstate == SOCKET_IS_NONBLOCKING) { + break; + } + } while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE); + if (len > 0) + return PyInt_FromLong(len); + else + return PySSL_SetError(self, len, __FILE__, __LINE__); +} + +PyDoc_STRVAR(PySSL_SSLwrite_doc, +"write(s) -> len\n\ +\n\ +Writes the string s into the SSL object. Returns the number\n\ +of bytes written."); + +static PyObject *PySSL_SSLpending(PySSLObject *self) +{ + int count = 0; + + PySSL_BEGIN_ALLOW_THREADS + count = SSL_pending(self->ssl); + PySSL_END_ALLOW_THREADS + if (count < 0) + return PySSL_SetError(self, count, __FILE__, __LINE__); + else + return PyInt_FromLong(count); +} + +PyDoc_STRVAR(PySSL_SSLpending_doc, +"pending() -> count\n\ +\n\ +Returns the number of already decrypted bytes available for read,\n\ +pending on the connection.\n"); + +static PyObject *PySSL_SSLread(PySSLObject *self, PyObject *args) +{ + PyObject *buf; + int count = 0; + int len = 1024; + int sockstate; + int err; + int nonblocking; + + if (!PyArg_ParseTuple(args, "|i:read", &len)) + return NULL; + + if (!(buf = PyString_FromStringAndSize((char *) 0, len))) + return NULL; + + /* just in case the blocking state of the socket has been changed */ + nonblocking = (self->Socket->sock_timeout >= 0.0); + BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking); + BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking); + + /* first check if there are bytes ready to be read */ + PySSL_BEGIN_ALLOW_THREADS + count = SSL_pending(self->ssl); + PySSL_END_ALLOW_THREADS + + if (!count) { + sockstate = check_socket_and_wait_for_timeout(self->Socket, 0); + if (sockstate == SOCKET_HAS_TIMED_OUT) { + PyErr_SetString(PySSLErrorObject, + "The read operation timed out"); + Py_DECREF(buf); + return NULL; + } else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) { + PyErr_SetString(PySSLErrorObject, + "Underlying socket too large for select()."); + Py_DECREF(buf); + return NULL; + } else if (sockstate == SOCKET_HAS_BEEN_CLOSED) { + if (SSL_get_shutdown(self->ssl) != + SSL_RECEIVED_SHUTDOWN) + { + Py_DECREF(buf); + PyErr_SetString(PySSLErrorObject, + "Socket closed without SSL shutdown handshake"); + return NULL; + } else { + /* should contain a zero-length string */ + _PyString_Resize(&buf, 0); + return buf; + } + } + } + do { + err = 0; + PySSL_BEGIN_ALLOW_THREADS + count = SSL_read(self->ssl, PyString_AsString(buf), len); + err = SSL_get_error(self->ssl, count); + PySSL_END_ALLOW_THREADS + if(PyErr_CheckSignals()) { + Py_DECREF(buf); + return NULL; + } + if (err == SSL_ERROR_WANT_READ) { + sockstate = check_socket_and_wait_for_timeout(self->Socket, 0); + } else if (err == SSL_ERROR_WANT_WRITE) { + sockstate = check_socket_and_wait_for_timeout(self->Socket, 1); + } else if ((err == SSL_ERROR_ZERO_RETURN) && + (SSL_get_shutdown(self->ssl) == + SSL_RECEIVED_SHUTDOWN)) + { + _PyString_Resize(&buf, 0); + return buf; + } else { + sockstate = SOCKET_OPERATION_OK; + } + if (sockstate == SOCKET_HAS_TIMED_OUT) { + PyErr_SetString(PySSLErrorObject, + "The read operation timed out"); + Py_DECREF(buf); + return NULL; + } else if (sockstate == SOCKET_IS_NONBLOCKING) { + break; + } + } while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE); + if (count <= 0) { + Py_DECREF(buf); + return PySSL_SetError(self, count, __FILE__, __LINE__); + } + if (count != len) + _PyString_Resize(&buf, count); + return buf; +} + +PyDoc_STRVAR(PySSL_SSLread_doc, +"read([len]) -> string\n\ +\n\ +Read up to len bytes from the SSL socket."); + +static PyObject *PySSL_SSLshutdown(PySSLObject *self) +{ + int err, ssl_err, sockstate, nonblocking; + int zeros = 0; + + /* Guard against closed socket */ + if (self->Socket->sock_fd < 0) { + PyErr_SetString(PySSLErrorObject, + "Underlying socket has been closed."); + return NULL; + } + + /* Just in case the blocking state of the socket has been changed */ + nonblocking = (self->Socket->sock_timeout >= 0.0); + BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking); + BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking); + + while (1) { + PySSL_BEGIN_ALLOW_THREADS + /* Disable read-ahead so that unwrap can work correctly. + * Otherwise OpenSSL might read in too much data, + * eating clear text data that happens to be + * transmitted after the SSL shutdown. + * Should be safe to call repeatedly everytime this + * function is used and the shutdown_seen_zero != 0 + * condition is met. + */ + if (self->shutdown_seen_zero) + SSL_set_read_ahead(self->ssl, 0); + err = SSL_shutdown(self->ssl); + PySSL_END_ALLOW_THREADS + /* If err == 1, a secure shutdown with SSL_shutdown() is complete */ + if (err > 0) + break; + if (err == 0) { + /* Don't loop endlessly; instead preserve legacy + behaviour of trying SSL_shutdown() only twice. + This looks necessary for OpenSSL < 0.9.8m */ + if (++zeros > 1) + break; + /* Shutdown was sent, now try receiving */ + self->shutdown_seen_zero = 1; + continue; + } + + /* Possibly retry shutdown until timeout or failure */ + ssl_err = SSL_get_error(self->ssl, err); + if (ssl_err == SSL_ERROR_WANT_READ) + sockstate = check_socket_and_wait_for_timeout(self->Socket, 0); + else if (ssl_err == SSL_ERROR_WANT_WRITE) + sockstate = check_socket_and_wait_for_timeout(self->Socket, 1); + else + break; + if (sockstate == SOCKET_HAS_TIMED_OUT) { + if (ssl_err == SSL_ERROR_WANT_READ) + PyErr_SetString(PySSLErrorObject, + "The read operation timed out"); + else + PyErr_SetString(PySSLErrorObject, + "The write operation timed out"); + return NULL; + } + else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) { + PyErr_SetString(PySSLErrorObject, + "Underlying socket too large for select()."); + return NULL; + } + else if (sockstate != SOCKET_OPERATION_OK) + /* Retain the SSL error code */ + break; + } + + if (err < 0) + return PySSL_SetError(self, err, __FILE__, __LINE__); + else { + Py_INCREF(self->Socket); + return (PyObject *) (self->Socket); + } +} + +PyDoc_STRVAR(PySSL_SSLshutdown_doc, +"shutdown(s) -> socket\n\ +\n\ +Does the SSL shutdown handshake with the remote end, and returns\n\ +the underlying socket object."); + +static PyMethodDef PySSLMethods[] = { + {"wrap_accepted", (PyCFunction)PySSL_SSLwrap_accepted, METH_VARARGS, + PySSL_SSLwrap_accepted_doc}, + {"do_handshake", (PyCFunction)PySSL_SSLdo_handshake, METH_NOARGS}, + {"write", (PyCFunction)PySSL_SSLwrite, METH_VARARGS, + PySSL_SSLwrite_doc}, + {"read", (PyCFunction)PySSL_SSLread, METH_VARARGS, + PySSL_SSLread_doc}, + {"pending", (PyCFunction)PySSL_SSLpending, METH_NOARGS, + PySSL_SSLpending_doc}, + {"server", (PyCFunction)PySSL_server, METH_NOARGS}, + {"issuer", (PyCFunction)PySSL_issuer, METH_NOARGS}, + {"peer_certificate", (PyCFunction)PySSL_peercert, METH_VARARGS, + PySSL_peercert_doc}, + {"cipher", (PyCFunction)PySSL_cipher, METH_NOARGS}, + {"shutdown", (PyCFunction)PySSL_SSLshutdown, METH_NOARGS, + PySSL_SSLshutdown_doc}, + {NULL, NULL} +}; + +static PyObject *PySSL_getattr(PySSLObject *self, char *name) +{ + return Py_FindMethod(PySSLMethods, (PyObject *)self, name); +} + +static PyTypeObject PySSL_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "ssl.SSLContext", /*tp_name*/ + sizeof(PySSLObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)PySSL_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)PySSL_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ +}; + +#ifdef HAVE_OPENSSL_RAND + +/* helper routines for seeding the SSL PRNG */ +static PyObject * +PySSL_RAND_add(PyObject *self, PyObject *args) +{ + char *buf; + int len; + double entropy; + + if (!PyArg_ParseTuple(args, "s#d:RAND_add", &buf, &len, &entropy)) + return NULL; + RAND_add(buf, len, entropy); + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(PySSL_RAND_add_doc, +"RAND_add(string, entropy)\n\ +\n\ +Mix string into the OpenSSL PRNG state. entropy (a float) is a lower\n\ +bound on the entropy contained in string. See RFC 1750."); + +static PyObject * +PySSL_RAND_status(PyObject *self) +{ + return PyInt_FromLong(RAND_status()); +} + +PyDoc_STRVAR(PySSL_RAND_status_doc, +"RAND_status() -> 0 or 1\n\ +\n\ +Returns 1 if the OpenSSL PRNG has been seeded with enough data and 0 if not.\n\ +It is necessary to seed the PRNG with RAND_add() on some platforms before\n\ +using the ssl() function."); + +static PyObject * +PySSL_RAND_egd(PyObject *self, PyObject *arg) +{ + int bytes; + + if (!PyString_Check(arg)) + return PyErr_Format(PyExc_TypeError, + "RAND_egd() expected string, found %s", + Py_TYPE(arg)->tp_name); + bytes = RAND_egd(PyString_AS_STRING(arg)); + if (bytes == -1) { + PyErr_SetString(PySSLErrorObject, + "EGD connection failed or EGD did not return " + "enough data to seed the PRNG"); + return NULL; + } + return PyInt_FromLong(bytes); +} + +PyDoc_STRVAR(PySSL_RAND_egd_doc, +"RAND_egd(path) -> bytes\n\ +\n\ +Queries the entropy gather daemon (EGD) on the socket named by 'path'.\n\ +Returns number of bytes read. Raises SSLError if connection to EGD\n\ +fails or if it does provide enough data to seed PRNG."); + +#endif + +/* List of functions exported by this module. */ + +static PyMethodDef PySSL_methods[] = { + {"sslwrap", PySSL_sslwrap, + METH_VARARGS, sslwrap_doc}, + {"_test_decode_cert", PySSL_test_decode_certificate, + METH_VARARGS}, +#ifdef HAVE_OPENSSL_RAND + {"RAND_add", PySSL_RAND_add, METH_VARARGS, + PySSL_RAND_add_doc}, + {"RAND_egd", PySSL_RAND_egd, METH_O, + PySSL_RAND_egd_doc}, + {"RAND_status", (PyCFunction)PySSL_RAND_status, METH_NOARGS, + PySSL_RAND_status_doc}, +#endif + {NULL, NULL} /* Sentinel */ +}; + + +#ifdef WITH_THREAD + +/* an implementation of OpenSSL threading operations in terms + of the Python C thread library */ + +static PyThread_type_lock *_ssl_locks = NULL; + +static unsigned long _ssl_thread_id_function (void) { + return PyThread_get_thread_ident(); +} + +static void _ssl_thread_locking_function (int mode, int n, const char *file, int line) { + /* this function is needed to perform locking on shared data + structures. (Note that OpenSSL uses a number of global data + structures that will be implicitly shared whenever multiple threads + use OpenSSL.) Multi-threaded applications will crash at random if + it is not set. + + locking_function() must be able to handle up to CRYPTO_num_locks() + different mutex locks. It sets the n-th lock if mode & CRYPTO_LOCK, and + releases it otherwise. + + file and line are the file number of the function setting the + lock. They can be useful for debugging. + */ + + if ((_ssl_locks == NULL) || + (n < 0) || ((unsigned)n >= _ssl_locks_count)) + return; + + if (mode & CRYPTO_LOCK) { + PyThread_acquire_lock(_ssl_locks[n], 1); + } else { + PyThread_release_lock(_ssl_locks[n]); + } +} + +static int _setup_ssl_threads(void) { + + unsigned int i; + + if (_ssl_locks == NULL) { + _ssl_locks_count = CRYPTO_num_locks(); + _ssl_locks = (PyThread_type_lock *) + malloc(sizeof(PyThread_type_lock) * _ssl_locks_count); + if (_ssl_locks == NULL) + return 0; + memset(_ssl_locks, 0, sizeof(PyThread_type_lock) * _ssl_locks_count); + for (i = 0; i < _ssl_locks_count; i++) { + _ssl_locks[i] = PyThread_allocate_lock(); + if (_ssl_locks[i] == NULL) { + unsigned int j; + for (j = 0; j < i; j++) { + PyThread_free_lock(_ssl_locks[j]); + } + free(_ssl_locks); + return 0; + } + } + CRYPTO_set_locking_callback(_ssl_thread_locking_function); + CRYPTO_set_id_callback(_ssl_thread_id_function); + } + return 1; +} + +#endif /* def HAVE_THREAD */ + +PyDoc_STRVAR(module_doc, +"Implementation module for SSL socket operations. See the socket module\n\ +for documentation."); + +PyMODINIT_FUNC +init_forge_ssl(void) +{ + PyObject *m, *d; + + Py_TYPE(&PySSL_Type) = &PyType_Type; + + m = Py_InitModule3("_forge_ssl", PySSL_methods, module_doc); + if (m == NULL) + return; + d = PyModule_GetDict(m); + + /* Load _socket module and its C API */ + if (PySocketModule_ImportModuleAndAPI()) + return; + + /* Init OpenSSL */ + SSL_load_error_strings(); + SSL_library_init(); +#ifdef WITH_THREAD + /* note that this will start threading if not already started */ + if (!_setup_ssl_threads()) { + return; + } +#endif + OpenSSL_add_all_algorithms(); + + /* Add symbols to module dict */ + PySSLErrorObject = PyErr_NewException("ssl.SSLError", + PySocketModule.error, + NULL); + if (PySSLErrorObject == NULL) + return; + if (PyDict_SetItemString(d, "SSLError", PySSLErrorObject) != 0) + return; + if (PyDict_SetItemString(d, "SSLType", + (PyObject *)&PySSL_Type) != 0) + return; + PyModule_AddIntConstant(m, "SSL_ERROR_ZERO_RETURN", + PY_SSL_ERROR_ZERO_RETURN); + PyModule_AddIntConstant(m, "SSL_ERROR_WANT_READ", + PY_SSL_ERROR_WANT_READ); + PyModule_AddIntConstant(m, "SSL_ERROR_WANT_WRITE", + PY_SSL_ERROR_WANT_WRITE); + PyModule_AddIntConstant(m, "SSL_ERROR_WANT_X509_LOOKUP", + PY_SSL_ERROR_WANT_X509_LOOKUP); + PyModule_AddIntConstant(m, "SSL_ERROR_SYSCALL", + PY_SSL_ERROR_SYSCALL); + PyModule_AddIntConstant(m, "SSL_ERROR_SSL", + PY_SSL_ERROR_SSL); + PyModule_AddIntConstant(m, "SSL_ERROR_WANT_CONNECT", + PY_SSL_ERROR_WANT_CONNECT); + /* non ssl.h errorcodes */ + PyModule_AddIntConstant(m, "SSL_ERROR_EOF", + PY_SSL_ERROR_EOF); + PyModule_AddIntConstant(m, "SSL_ERROR_INVALID_ERROR_CODE", + PY_SSL_ERROR_INVALID_ERROR_CODE); + /* cert requirements */ + PyModule_AddIntConstant(m, "CERT_NONE", + PY_SSL_CERT_NONE); + PyModule_AddIntConstant(m, "CERT_OPTIONAL", + PY_SSL_CERT_OPTIONAL); + PyModule_AddIntConstant(m, "CERT_REQUIRED", + PY_SSL_CERT_REQUIRED); + + /* protocol versions */ + PyModule_AddIntConstant(m, "PROTOCOL_SSLv2", + PY_SSL_VERSION_SSL2); + PyModule_AddIntConstant(m, "PROTOCOL_SSLv3", + PY_SSL_VERSION_SSL3); + PyModule_AddIntConstant(m, "PROTOCOL_SSLv23", + PY_SSL_VERSION_SSL23); + PyModule_AddIntConstant(m, "PROTOCOL_TLSv1", + PY_SSL_VERSION_TLS1); + + /* session cache modes */ + PyModule_AddIntConstant(m, "SESS_CACHE_OFF", + PY_SSL_SESS_CACHE_OFF); + PyModule_AddIntConstant(m, "SESS_CACHE_CLIENT", + PY_SSL_SESS_CACHE_CLIENT); + PyModule_AddIntConstant(m, "SESS_CACHE_SERVER", + PY_SSL_SESS_CACHE_SERVER); + PyModule_AddIntConstant(m, "SESS_CACHE_BOTH", + PY_SSL_SESS_CACHE_BOTH); +} diff --git a/school/node_modules/node-forge/tests/forge_ssl/forge/socketmodule.h b/school/node_modules/node-forge/tests/forge_ssl/forge/socketmodule.h new file mode 100644 index 0000000..a4415b5 --- /dev/null +++ b/school/node_modules/node-forge/tests/forge_ssl/forge/socketmodule.h @@ -0,0 +1,268 @@ +/* Socket module header file */ + +/* Includes needed for the sockaddr_* symbols below */ +#ifndef MS_WINDOWS +#ifdef __VMS +# include <socket.h> +# else +# include <sys/socket.h> +# endif +# include <netinet/in.h> +# if !(defined(__BEOS__) || defined(__CYGWIN__) || (defined(PYOS_OS2) && defined(PYCC_VACPP))) +# include <netinet/tcp.h> +# endif + +#else /* MS_WINDOWS */ +# include <winsock2.h> +# include <ws2tcpip.h> +/* VC6 is shipped with old platform headers, and does not have MSTcpIP.h + * Separate SDKs have all the functions we want, but older ones don't have + * any version information. + * I use SIO_GET_MULTICAST_FILTER to detect a decent SDK. + */ +# ifdef SIO_GET_MULTICAST_FILTER +# include <MSTcpIP.h> /* for SIO_RCVALL */ +# define HAVE_ADDRINFO +# define HAVE_SOCKADDR_STORAGE +# define HAVE_GETADDRINFO +# define HAVE_GETNAMEINFO +# define ENABLE_IPV6 +# else +typedef int socklen_t; +# endif /* IPPROTO_IPV6 */ +#endif /* MS_WINDOWS */ + +#ifdef HAVE_SYS_UN_H +# include <sys/un.h> +#else +# undef AF_UNIX +#endif + +#ifdef HAVE_LINUX_NETLINK_H +# ifdef HAVE_ASM_TYPES_H +# include <asm/types.h> +# endif +# include <linux/netlink.h> +#else +# undef AF_NETLINK +#endif + +#ifdef HAVE_BLUETOOTH_BLUETOOTH_H +/* +#include <bluetooth/bluetooth.h> +#include <bluetooth/rfcomm.h> +#include <bluetooth/l2cap.h> +#include <bluetooth/sco.h> +#include <bluetooth/hci.h> +*/ +#endif + +#ifdef HAVE_BLUETOOTH_H +#include <bluetooth.h> +#endif + +#ifdef HAVE_NETPACKET_PACKET_H +# include <sys/ioctl.h> +# include <net/if.h> +# include <netpacket/packet.h> +#endif + +#ifdef HAVE_LINUX_TIPC_H +# include <linux/tipc.h> +#endif + +#ifndef Py__SOCKET_H +#define Py__SOCKET_H +#ifdef __cplusplus +extern "C" { +#endif + +/* Python module and C API name */ +#define PySocket_MODULE_NAME "_socket" +#define PySocket_CAPI_NAME "CAPI" + +/* Abstract the socket file descriptor type */ +#ifdef MS_WINDOWS +typedef SOCKET SOCKET_T; +# ifdef MS_WIN64 +# define SIZEOF_SOCKET_T 8 +# else +# define SIZEOF_SOCKET_T 4 +# endif +#else +typedef int SOCKET_T; +# define SIZEOF_SOCKET_T SIZEOF_INT +#endif + +/* Socket address */ +typedef union sock_addr { + struct sockaddr_in in; +#ifdef AF_UNIX + struct sockaddr_un un; +#endif +#ifdef AF_NETLINK + struct sockaddr_nl nl; +#endif +#ifdef ENABLE_IPV6 + struct sockaddr_in6 in6; + struct sockaddr_storage storage; +#endif +#ifdef HAVE_BLUETOOTH_BLUETOOTH_H +/* + struct sockaddr_l2 bt_l2; + struct sockaddr_rc bt_rc; + struct sockaddr_sco bt_sco; + struct sockaddr_hci bt_hci; +*/ +#endif +#ifdef HAVE_NETPACKET_PACKET_H + struct sockaddr_ll ll; +#endif +} sock_addr_t; + +/* The object holding a socket. It holds some extra information, + like the address family, which is used to decode socket address + arguments properly. */ + +typedef struct { + PyObject_HEAD + SOCKET_T sock_fd; /* Socket file descriptor */ + int sock_family; /* Address family, e.g., AF_INET */ + int sock_type; /* Socket type, e.g., SOCK_STREAM */ + int sock_proto; /* Protocol type, usually 0 */ + PyObject *(*errorhandler)(void); /* Error handler; checks + errno, returns NULL and + sets a Python exception */ + double sock_timeout; /* Operation timeout in seconds; + 0.0 means non-blocking */ +} PySocketSockObject; + +/* --- C API ----------------------------------------------------*/ + +/* Short explanation of what this C API export mechanism does + and how it works: + + The _ssl module needs access to the type object defined in + the _socket module. Since cross-DLL linking introduces a lot of + problems on many platforms, the "trick" is to wrap the + C API of a module in a struct which then gets exported to + other modules via a PyCObject. + + The code in socketmodule.c defines this struct (which currently + only contains the type object reference, but could very + well also include other C APIs needed by other modules) + and exports it as PyCObject via the module dictionary + under the name "CAPI". + + Other modules can now include the socketmodule.h file + which defines the needed C APIs to import and set up + a static copy of this struct in the importing module. + + After initialization, the importing module can then + access the C APIs from the _socket module by simply + referring to the static struct, e.g. + + Load _socket module and its C API; this sets up the global + PySocketModule: + + if (PySocketModule_ImportModuleAndAPI()) + return; + + + Now use the C API as if it were defined in the using + module: + + if (!PyArg_ParseTuple(args, "O!|zz:ssl", + + PySocketModule.Sock_Type, + + (PyObject*)&Sock, + &key_file, &cert_file)) + return NULL; + + Support could easily be extended to export more C APIs/symbols + this way. Currently, only the type object is exported, + other candidates would be socket constructors and socket + access functions. + +*/ + +/* C API for usage by other Python modules */ +typedef struct { + PyTypeObject *Sock_Type; + PyObject *error; +} PySocketModule_APIObject; + +/* XXX The net effect of the following appears to be to define a function + XXX named PySocketModule_APIObject in _ssl.c. It's unclear why it isn't + XXX defined there directly. + + >>> It's defined here because other modules might also want to use + >>> the C API. + +*/ +#ifndef PySocket_BUILDING_SOCKET + +/* --- C API ----------------------------------------------------*/ + +/* Interfacestructure to C API for other modules. + Call PySocketModule_ImportModuleAndAPI() to initialize this + structure. After that usage is simple: + + if (!PyArg_ParseTuple(args, "O!|zz:ssl", + &PySocketModule.Sock_Type, (PyObject*)&Sock, + &key_file, &cert_file)) + return NULL; + ... +*/ + +static +PySocketModule_APIObject PySocketModule; + +/* You *must* call this before using any of the functions in + PySocketModule and check its outcome; otherwise all accesses will + result in a segfault. Returns 0 on success. */ + +#ifndef DPRINTF +# define DPRINTF if (0) printf +#endif + +static +int PySocketModule_ImportModuleAndAPI(void) +{ + PyObject *mod = 0, *v = 0; + char *apimodule = PySocket_MODULE_NAME; + char *apiname = PySocket_CAPI_NAME; + void *api; + + DPRINTF("Importing the %s C API...\n", apimodule); + mod = PyImport_ImportModuleNoBlock(apimodule); + if (mod == NULL) + goto onError; + DPRINTF(" %s package found\n", apimodule); + v = PyObject_GetAttrString(mod, apiname); + if (v == NULL) + goto onError; + Py_DECREF(mod); + DPRINTF(" API object %s found\n", apiname); + api = PyCObject_AsVoidPtr(v); + if (api == NULL) + goto onError; + Py_DECREF(v); + memcpy(&PySocketModule, api, sizeof(PySocketModule)); + DPRINTF(" API object loaded and initialized.\n"); + return 0; + + onError: + DPRINTF(" not found.\n"); + Py_XDECREF(mod); + Py_XDECREF(v); + return -1; +} + +#endif /* !PySocket_BUILDING_SOCKET */ + +#ifdef __cplusplus +} +#endif +#endif /* !Py__SOCKET_H */ diff --git a/school/node_modules/node-forge/tests/forge_ssl/forge/ssl.py b/school/node_modules/node-forge/tests/forge_ssl/forge/ssl.py new file mode 100644 index 0000000..aa9fc14 --- /dev/null +++ b/school/node_modules/node-forge/tests/forge_ssl/forge/ssl.py @@ -0,0 +1,486 @@ +# Wrapper module for _ssl, providing some additional facilities +# implemented in Python. Written by Bill Janssen. + +"""\ +This module provides some more Pythonic support for SSL. + +Object types: + + SSLSocket -- subtype of socket.socket which does SSL over the socket + +Exceptions: + + SSLError -- exception raised for I/O errors + +Functions: + + cert_time_to_seconds -- convert time string used for certificate + notBefore and notAfter functions to integer + seconds past the Epoch (the time values + returned from time.time()) + + fetch_server_certificate (HOST, PORT) -- fetch the certificate provided + by the server running on HOST at port PORT. No + validation of the certificate is performed. + +Integer constants: + +SSL_ERROR_ZERO_RETURN +SSL_ERROR_WANT_READ +SSL_ERROR_WANT_WRITE +SSL_ERROR_WANT_X509_LOOKUP +SSL_ERROR_SYSCALL +SSL_ERROR_SSL +SSL_ERROR_WANT_CONNECT + +SSL_ERROR_EOF +SSL_ERROR_INVALID_ERROR_CODE + +The following group define certificate requirements that one side is +allowing/requiring from the other side: + +CERT_NONE - no certificates from the other side are required (or will + be looked at if provided) +CERT_OPTIONAL - certificates are not required, but if provided will be + validated, and if validation fails, the connection will + also fail +CERT_REQUIRED - certificates are required, and will be validated, and + if validation fails, the connection will also fail + +The following constants identify various SSL protocol variants: + +PROTOCOL_SSLv2 +PROTOCOL_SSLv3 +PROTOCOL_SSLv23 +PROTOCOL_TLSv1 + +The following constants identify various SSL session caching modes: + +SESS_CACHE_OFF +SESS_CACHE_CLIENT +SESS_CACHE_SERVER +SESS_CACHE_BOTH +""" + +import textwrap + +import _forge_ssl # if we can't import it, let the error propagate + +from _forge_ssl import SSLError +from _forge_ssl import CERT_NONE, CERT_OPTIONAL, CERT_REQUIRED +from _forge_ssl import PROTOCOL_SSLv2, PROTOCOL_SSLv3, PROTOCOL_SSLv23, PROTOCOL_TLSv1 +from _forge_ssl import SESS_CACHE_OFF, SESS_CACHE_CLIENT, SESS_CACHE_SERVER, SESS_CACHE_BOTH +from _forge_ssl import RAND_status, RAND_egd, RAND_add +from _forge_ssl import \ + SSL_ERROR_ZERO_RETURN, \ + SSL_ERROR_WANT_READ, \ + SSL_ERROR_WANT_WRITE, \ + SSL_ERROR_WANT_X509_LOOKUP, \ + SSL_ERROR_SYSCALL, \ + SSL_ERROR_SSL, \ + SSL_ERROR_WANT_CONNECT, \ + SSL_ERROR_EOF, \ + SSL_ERROR_INVALID_ERROR_CODE + +from socket import socket, _fileobject, _delegate_methods +from socket import error as socket_error +from socket import getnameinfo as _getnameinfo +import base64 # for DER-to-PEM translation +import errno + +class SSLSocket(socket): + + """This class implements a subtype of socket.socket that wraps + the underlying OS socket in an SSL context when necessary, and + provides read and write methods over that channel.""" + + def __init__(self, parent_socket, sock, keyfile=None, certfile=None, + server_side=False, cert_reqs=CERT_NONE, + ssl_version=PROTOCOL_SSLv23, + sess_cache_mode=SESS_CACHE_SERVER, + sess_id_ctx=None, + ca_certs=None, + do_handshake_on_connect=True, + suppress_ragged_eofs=True): + socket.__init__(self, _sock=sock._sock) + # The initializer for socket overrides the methods send(), recv(), etc. + # in the instancce, which we don't need -- but we want to provide the + # methods defined in SSLSocket. + for attr in _delegate_methods: + try: + delattr(self, attr) + except AttributeError: + pass + + if certfile and not keyfile: + keyfile = certfile + + create = True + connected = False + if not server_side: + # see if it's connected + try: + socket.getpeername(self) + connected = True + except socket_error, e: + if e.errno != errno.ENOTCONN: + raise + # no, no connection yet + self._sslobj = None + create = False + if create: + # yes, create the SSL object + if parent_socket == None: + self._sslobj = _forge_ssl.sslwrap( + self._sock, + server_side, + keyfile, certfile, + cert_reqs, ssl_version, + sess_cache_mode, sess_id_ctx, + ca_certs) + else: + self._sslobj = parent_socket._sslobj.wrap_accepted(self._sock) + + if connected and do_handshake_on_connect: + self.do_handshake() + self.keyfile = keyfile + self.certfile = certfile + self.cert_reqs = cert_reqs + self.ssl_version = ssl_version + self.sess_cache_mode = sess_cache_mode + self.sess_id_ctx = sess_id_ctx + self.ca_certs = ca_certs + self.do_handshake_on_connect = do_handshake_on_connect + self.suppress_ragged_eofs = suppress_ragged_eofs + self._makefile_refs = 0 + + def read(self, len=1024): + + """Read up to LEN bytes and return them. + Return zero-length string on EOF.""" + + try: + return self._sslobj.read(len) + except SSLError, x: + if x.args[0] == SSL_ERROR_EOF and self.suppress_ragged_eofs: + return '' + else: + raise + + def write(self, data): + + """Write DATA to the underlying SSL channel. Returns + number of bytes of DATA actually transmitted.""" + + return self._sslobj.write(data) + + def getpeercert(self, binary_form=False): + + """Returns a formatted version of the data in the + certificate provided by the other end of the SSL channel. + Return None if no certificate was provided, {} if a + certificate was provided, but not validated.""" + + return self._sslobj.peer_certificate(binary_form) + + def cipher(self): + + if not self._sslobj: + return None + else: + return self._sslobj.cipher() + + def send(self, data, flags=0): + if self._sslobj: + if flags != 0: + raise ValueError( + "non-zero flags not allowed in calls to send() on %s" % + self.__class__) + while True: + try: + v = self._sslobj.write(data) + except SSLError, x: + if x.args[0] == SSL_ERROR_WANT_READ: + return 0 + elif x.args[0] == SSL_ERROR_WANT_WRITE: + return 0 + else: + raise + else: + return v + else: + return socket.send(self, data, flags) + + def sendto(self, data, addr, flags=0): + if self._sslobj: + raise ValueError("sendto not allowed on instances of %s" % + self.__class__) + else: + return socket.sendto(self, data, addr, flags) + + def sendall(self, data, flags=0): + if self._sslobj: + if flags != 0: + raise ValueError( + "non-zero flags not allowed in calls to sendall() on %s" % + self.__class__) + amount = len(data) + count = 0 + while (count < amount): + v = self.send(data[count:]) + count += v + return amount + else: + return socket.sendall(self, data, flags) + + def recv(self, buflen=1024, flags=0): + if self._sslobj: + if flags != 0: + raise ValueError( + "non-zero flags not allowed in calls to recv() on %s" % + self.__class__) + return self.read(buflen) + else: + return socket.recv(self, buflen, flags) + + def recv_into(self, buffer, nbytes=None, flags=0): + if buffer and (nbytes is None): + nbytes = len(buffer) + elif nbytes is None: + nbytes = 1024 + if self._sslobj: + if flags != 0: + raise ValueError( + "non-zero flags not allowed in calls to recv_into() on %s" % + self.__class__) + tmp_buffer = self.read(nbytes) + v = len(tmp_buffer) + buffer[:v] = tmp_buffer + return v + else: + return socket.recv_into(self, buffer, nbytes, flags) + + def recvfrom(self, addr, buflen=1024, flags=0): + if self._sslobj: + raise ValueError("recvfrom not allowed on instances of %s" % + self.__class__) + else: + return socket.recvfrom(self, addr, buflen, flags) + + def recvfrom_into(self, buffer, nbytes=None, flags=0): + if self._sslobj: + raise ValueError("recvfrom_into not allowed on instances of %s" % + self.__class__) + else: + return socket.recvfrom_into(self, buffer, nbytes, flags) + + def pending(self): + if self._sslobj: + return self._sslobj.pending() + else: + return 0 + + def unwrap(self): + if self._sslobj: + try: + # if connected then shutdown + self.getpeername() + s = self._sslobj.shutdown() + except: + s = self._sock + self._sslobj = None + return s + else: + raise ValueError("No SSL wrapper around " + str(self)) + + def shutdown(self, how): + self._sslobj = None + socket.shutdown(self, how) + + def close(self): + if self._makefile_refs < 1: + if self._sslobj: + self.unwrap() + socket.close(self) + else: + self._makefile_refs -= 1 + + def do_handshake(self): + + """Perform a TLS/SSL handshake.""" + + self._sslobj.do_handshake() + + def connect(self, addr): + + """Connects to remote ADDR, and then wraps the connection in + an SSL channel.""" + + # Here we assume that the socket is client-side, and not + # connected at the time of the call. We connect it, then wrap it. + if self._sslobj: + raise ValueError("attempt to connect already-connected SSLSocket!") + socket.connect(self, addr) + self._sslobj = _forge_ssl.sslwrap(self._sock, False, + self.keyfile, self.certfile, + self.cert_reqs, self.ssl_version, + self.sess_cache_mode, + self.sess_id_ctx, + self.ca_certs) + if self.do_handshake_on_connect: + self.do_handshake() + + def accept(self): + + """Accepts a new connection from a remote client, and returns + a tuple containing that new connection wrapped with a server-side + SSL channel, and the address of the remote client.""" + + newsock, addr = socket.accept(self) + return (SSLSocket(self, + newsock, + keyfile=self.keyfile, + certfile=self.certfile, + server_side=True, + cert_reqs=self.cert_reqs, + ssl_version=self.ssl_version, + sess_cache_mode=self.sess_cache_mode, + sess_id_ctx=self.sess_id_ctx, + ca_certs=self.ca_certs, + do_handshake_on_connect=self.do_handshake_on_connect, + suppress_ragged_eofs=self.suppress_ragged_eofs), + addr) + + def makefile(self, mode='r', bufsize=-1): + + """Make and return a file-like object that + works with the SSL connection. Just use the code + from the socket module.""" + + self._makefile_refs += 1 + # close=True so as to decrement the reference count when done with + # the file-like object. + return _fileobject(self, mode, bufsize, close=True) + + + +def wrap_socket(sock, parent_socket=None, keyfile=None, certfile=None, + server_side=False, cert_reqs=CERT_NONE, + ssl_version=PROTOCOL_SSLv23, + sess_cache_mode=SESS_CACHE_SERVER, + sess_id_ctx=None, + ca_certs=None, + do_handshake_on_connect=True, + suppress_ragged_eofs=True): + + return SSLSocket(parent_socket, + sock, keyfile=keyfile, certfile=certfile, + server_side=server_side, cert_reqs=cert_reqs, + ssl_version=ssl_version, + sess_cache_mode=sess_cache_mode, + sess_id_ctx=sess_id_ctx, + ca_certs=ca_certs, + do_handshake_on_connect=do_handshake_on_connect, + suppress_ragged_eofs=suppress_ragged_eofs) + + +# some utility functions + +def cert_time_to_seconds(cert_time): + + """Takes a date-time string in standard ASN1_print form + ("MON DAY 24HOUR:MINUTE:SEC YEAR TIMEZONE") and return + a Python time value in seconds past the epoch.""" + + import time + return time.mktime(time.strptime(cert_time, "%b %d %H:%M:%S %Y GMT")) + +PEM_HEADER = "-----BEGIN CERTIFICATE-----" +PEM_FOOTER = "-----END CERTIFICATE-----" + +def DER_cert_to_PEM_cert(der_cert_bytes): + + """Takes a certificate in binary DER format and returns the + PEM version of it as a string.""" + + if hasattr(base64, 'standard_b64encode'): + # preferred because older API gets line-length wrong + f = base64.standard_b64encode(der_cert_bytes) + return (PEM_HEADER + '\n' + + textwrap.fill(f, 64) + '\n' + + PEM_FOOTER + '\n') + else: + return (PEM_HEADER + '\n' + + base64.encodestring(der_cert_bytes) + + PEM_FOOTER + '\n') + +def PEM_cert_to_DER_cert(pem_cert_string): + + """Takes a certificate in ASCII PEM format and returns the + DER-encoded version of it as a byte sequence""" + + if not pem_cert_string.startswith(PEM_HEADER): + raise ValueError("Invalid PEM encoding; must start with %s" + % PEM_HEADER) + if not pem_cert_string.strip().endswith(PEM_FOOTER): + raise ValueError("Invalid PEM encoding; must end with %s" + % PEM_FOOTER) + d = pem_cert_string.strip()[len(PEM_HEADER):-len(PEM_FOOTER)] + return base64.decodestring(d) + +def get_server_certificate(addr, ssl_version=PROTOCOL_SSLv3, ca_certs=None): + + """Retrieve the certificate from the server at the specified address, + and return it as a PEM-encoded string. + If 'ca_certs' is specified, validate the server cert against it. + If 'ssl_version' is specified, use it in the connection attempt.""" + + host, port = addr + if (ca_certs is not None): + cert_reqs = CERT_REQUIRED + else: + cert_reqs = CERT_NONE + s = wrap_socket(socket(), ssl_version=ssl_version, + cert_reqs=cert_reqs, ca_certs=ca_certs) + s.connect(addr) + dercert = s.getpeercert(True) + s.close() + return DER_cert_to_PEM_cert(dercert) + +def get_protocol_name(protocol_code): + if protocol_code == PROTOCOL_TLSv1: + return "TLSv1" + elif protocol_code == PROTOCOL_SSLv23: + return "SSLv23" + elif protocol_code == PROTOCOL_SSLv2: + return "SSLv2" + elif protocol_code == PROTOCOL_SSLv3: + return "SSLv3" + else: + return "<unknown>" + + +# a replacement for the old socket.ssl function + +def sslwrap_simple(sock, keyfile=None, certfile=None): + + """A replacement for the old socket.ssl function. Designed + for compability with Python 2.5 and earlier. Will disappear in + Python 3.0.""" + + if hasattr(sock, "_sock"): + sock = sock._sock + + ssl_sock = _forge_ssl.sslwrap(sock, 0, keyfile, certfile, + CERT_NONE, PROTOCOL_SSLv23, + SESS_CACHE_SERVER, None, None) + try: + sock.getpeername() + except: + # no, no connection yet + pass + else: + # yes, do the handshake + ssl_sock.do_handshake() + + return ssl_sock diff --git a/school/node_modules/node-forge/tests/forge_ssl/setup.py b/school/node_modules/node-forge/tests/forge_ssl/setup.py new file mode 100644 index 0000000..350ae37 --- /dev/null +++ b/school/node_modules/node-forge/tests/forge_ssl/setup.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python + +from distutils.core import setup, Extension + +ssl = Extension('_forge_ssl', + sources = ['forge/_ssl.c']) + +setup (name = 'Forge SSL', + version = '1.0', + description = 'Python SSL with session cache support.', + ext_modules = [ssl], + py_modules = ['forge.ssl']) diff --git a/school/node_modules/node-forge/tests/form.html b/school/node_modules/node-forge/tests/form.html new file mode 100644 index 0000000..cfe9f94 --- /dev/null +++ b/school/node_modules/node-forge/tests/form.html @@ -0,0 +1,150 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head> + <title>Forge Form Test</title> + <link type="text/css" rel="stylesheet" media="all" href="screen.css" /> + <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script> + <script type="text/javascript" src="forge/debug.js"></script> + <script type="text/javascript" src="forge/util.js"></script> + <script type="text/javascript" src="forge/log.js"></script> + <script type="text/javascript" src="forge/form.js"></script> + <script type="text/javascript" src="form.js"></script> + + <link type="text/css" rel="stylesheet" media="all" href="screen.css" /> + </head> +<body> +<div class="nav"><a href="index.html">Forge Tests</a> / Form</div> + +<div class="header"> + <h1>Form Tests</h1> +</div> + +<div class="content"> + +<form id="form-1" class="ajax standard" method="post" action=""> + <fieldset> + <legend>Text</legend> + + <p> + <input name="text1" type="text" value="value1" /> + <input name="text2.sub1" type="text" value="value2" /> + <input name="text2.sub2[]" type="text" value="value3" /> + <input name="text2.sub2[]" type="text" value="value4" /> + <input name="text2.sub3[0]" type="text" value="value5" /> + <input name="text2.sub4[0][0]" type="text" value="value6" /> + <input name="text2.sub4[0][]" type="text" value="value7" /> + <input name="text2.sub5[foo][]" type="text" value="value8" /> + <input name="text2.sub5[dotted.name]" type="text" value="value9" /> + <input name="text2.sub6[]" type="text" value="value10" /> + <input name="text2.sub7[].@" type="text" value="value11" /> + <input name="text2.sub7[].@" type="text" value="value12" /> + <input name="text2.sub8[][].@" type="text" value="value13" /> + </p> + + <p> + <label>username <input name="username" type="text" value="username" /></label> + <label>password <input name="password" type="password" value="password" /></label> + </p> + + <p> + <label>password1.1 <input name="password1" type="password" value="password" /></label> + <label>password1.2 <input name="password1" type="password" value="password" /></label> + </p> + </fieldset> + + <fieldset> + <legend>Checkbox</legend> + + <p> + <label><input name="checkbox1" type="checkbox" value="c1" /> C1</label> + <label><input name="checkbox1" type="checkbox" value="c2" /> C1</label> + <label><input name="checkbox1" type="checkbox" value="c3" /> C1</label> + </p> + + <p> + <label><input name="checkbox2[]" type="checkbox" value="c1" /> C2[]</label> + <label><input name="checkbox2[]" type="checkbox" value="c2" /> C2[]</label> + <label><input name="checkbox2[3]" type="checkbox" value="c3" /> C2[3]</label> + <label><input name="checkbox2[]" type="checkbox" value="c4" /> C2[]</label> + <label><input name="checkbox2.sub1" type="checkbox" value="c4" /> C2.sub1</label> + </p> + + <p> + <label><input name="checkbox3.sub1" type="checkbox" value="c1" /> C3.s1</label> + <label><input name="checkbox3.sub2" type="checkbox" value="c2" /> C3.s2</label> + <label><input name="checkbox3.sub2" type="checkbox" value="c3" /> C3.s2</label> + <label><input name="checkbox3[]" type="checkbox" value="c4" /> C3[]</label> + </p> + </fieldset> + + <fieldset> + <legend>Radio</legend> + + <p> + <label><input name="radio1" type="radio" value="r1" /> R1</label> + <label><input name="radio1" type="radio" value="r2" /> R1</label> + <label><input name="radio1" type="radio" value="r3" /> R1</label> + <label><input name="radio1" type="radio" value="r4" /> R1</label> + </p> + + <p> + <label><input name="radio2.sub1" type="radio" value="r1" /> R2.s1</label> + <label><input name="radio2.sub1" type="radio" value="r2" /> R2.s1</label> + <label><input name="radio2.sub2" type="radio" value="r3" /> R2.s2</label> + <label><input name="radio2.sub2" type="radio" value="r4" /> R2.s2</label> + </p> + </fieldset> + + <fieldset> + <legend>Select</legend> + <p> + <select name="select1"> + <option value="select1">Select 1</option> + <option value="select2">Select 2</option> + <option value="select3">Select 3</option> + </select> + </p> + + <p> + <select name="select2" multiple="multiple"> + <option value="select1">Select 1</option> + <option value="select2">Select 2</option> + <option value="select3">Select 3</option> + </select> + </p> + </fieldset> + + <fieldset> + <legend>Text Area</legend> + + <textarea name="textarea">Test text.</textarea> + </fieldset> + + <fieldset> + <legend>Buttons</legend> + + <p> + <button name="button1" type="submit" value="submit">Submit Form</button> + <button name="button2" type="reset" value="reset">Reset Form</button> + </p> + </fieldset> + + <fieldset> + <legend>Input Buttons</legend> + + <p> + <input name="submit" type="submit" value="Submit Form" /> + <input name="reset" type="reset" value="Reset Form" /> + </p> + </fieldset> +</form> + +<p>Result:</p> +<div id="result"></div> + +</div> + +</body> +</html> diff --git a/school/node_modules/node-forge/tests/form.js b/school/node_modules/node-forge/tests/form.js new file mode 100644 index 0000000..abfbab0 --- /dev/null +++ b/school/node_modules/node-forge/tests/form.js @@ -0,0 +1,40 @@ +/** + * Forge Form Tests + * + * @author Dave Longley + * + * Copyright (c) 2011 Digital Bazaar, Inc. All rights reserved. + */ +(function($) { +$(document).ready(function() +{ + // logging category + var cat = 'forge.tests.form'; + + // local alias + var forge = window.forge; + + $('form.ajax').each(function(i, form) + { + $(form).submit(function() + { + try + { + var f = forge.form.serialize($(this)); + forge.log.debug(cat, 'result:', JSON.stringify(f)); + $('#result').html(JSON.stringify(f)); + + /* dictionary test + var f = forge.form.serialize($(this), '.', {'username':'user'}); + forge.log.debug(cat, 'result:', JSON.stringify(f)); + */ + } + catch(e) + { + console.log('exception', e.stack); + } + return false; + }); + }); +}); +})(jQuery); diff --git a/school/node_modules/node-forge/tests/heartbleed.js b/school/node_modules/node-forge/tests/heartbleed.js new file mode 100644 index 0000000..b38869a --- /dev/null +++ b/school/node_modules/node-forge/tests/heartbleed.js @@ -0,0 +1,55 @@ +var forge = require('../js/forge'); +var net = require('net'); + +var socket = new net.Socket(); + +var client = forge.tls.createConnection({ + server: false, + verify: function(connection, verified, depth, certs) { + // skip verification for testing + return true; + }, + connected: function(connection) { + // heartbleeds 2k + console.log('[tls] connected'); + connection.prepareHeartbeatRequest('', 2048); + setTimeout(function() { + client.close(); + }, 1000); + }, + tlsDataReady: function(connection) { + // encrypted data is ready to be sent to the server + var data = connection.tlsData.getBytes(); + socket.write(data, 'binary'); + }, + dataReady: function(connection) { + // clear data from the server is ready + var data = connection.data.getBytes(); + console.log('[tls] received from the server: ' + data); + }, + heartbeatReceived: function(c, payload) { + console.log('Heartbleed:\n' + payload.toHex()); + client.close(); + }, + closed: function() { + console.log('[tls] disconnected'); + socket.end(); + }, + error: function(connection, error) { + console.log('[tls] error', error); + } +}); + +socket.on('connect', function() { + console.log('[socket] connected'); + client.handshake(); +}); +socket.on('data', function(data) { + client.process(data.toString('binary')); +}); +socket.on('end', function() { + console.log('[socket] disconnected'); +}); + +// connect +socket.connect(443, 'yahoo.com'); diff --git a/school/node_modules/node-forge/tests/http.html b/school/node_modules/node-forge/tests/http.html new file mode 100644 index 0000000..3bdf941 --- /dev/null +++ b/school/node_modules/node-forge/tests/http.html @@ -0,0 +1,229 @@ +<html> + <head> + <link type="text/css" rel="stylesheet" media="all" href="screen.css" /> + <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js"></script> + <script type="text/javascript" src="forge/util.js"></script> + <script type="text/javascript" src="forge/socket.js"></script> + <script type="text/javascript" src="forge/http.js"></script> + <script type="text/javascript" src="forge/log.js"></script> + + <script type="text/javascript"> + //<![CDATA[ + // logging category + var cat = 'forge.tests.http'; + + window.forge.socketPool = + { + ready: function() + { + forge.log.debug(cat, 'SocketPool ready.'); + } + }; + + swfobject.embedSWF( + 'forge/SocketPool.swf', 'socketPool', '0', '0', '9.0.0', + false, {}, {allowscriptaccess: 'always'}, {}); + + // local aliases + var net = window.forge.net; + var http = window.forge.http; + var util = window.forge.util; + + var client; + + function client_init() + { + try + { + var sp = net.createSocketPool({ + flashId: 'socketPool', + policyPort: 19945, + msie: false + }); + client = http.createClient({ + //url: 'http://' + window.location.host, + socketPool: sp, + connections: 10 + }); + + document.getElementById('feedback').innerHTML = + 'HTTP client created'; + } + catch(ex) + { + forge.log.error(cat, ex); + } + return false; + } + + function client_cleanup() + { + var sp = client.socketPool; + client.destroy(); + sp.destroy(); + document.getElementById('feedback').innerHTML = + 'HTTP client cleaned up'; + return false; + } + + function client_send() + { + var request = http.createRequest({ + method: 'GET', + path: '/' + //body: 'echo=foo', + //headers: [{'Content-Type': 'application/x-www-form-urlencoded'}] + }); + + client.send({ + request: request, + connected: function(e) + { + forge.log.debug(cat, 'connected', e); + }, + headerReady: function(e) + { + forge.log.debug(cat, 'header ready', e); + }, + bodyReady: function(e) + { + forge.log.debug(cat, 'body ready', e); + }, + error: function(e) + { + forge.log.error(cat, 'error', e); + } + }); + document.getElementById('feedback').innerHTML = + 'HTTP request sent'; + return false; + } + + function client_send_10() + { + for(var i = 0; i < 10; ++i) + { + client_send(); + } + return false; + } + + function client_stress() + { + for(var i = 0; i < 10; ++i) + { + setTimeout(function() + { + for(var i = 0; i < 10; ++i) + { + client_send(); + } + }, 0); + } + return false; + } + + function client_cookies() + { + var cookie = + { + name: 'test-cookie', + value: 'test-value', + maxAge: -1, + secure: false, + path: '/' + }; + client.setCookie(cookie); + forge.log.debug(cat, 'cookie', client.getCookie('test-cookie')); + } + + function client_clear_cookies() + { + client.clearCookies(); + } + + function request_add_cookies() + { + var cookie1 = + { + name: 'test-cookie1', + value: 'test-value1', + maxAge: -1, + secure: false, + path: '/' + }; + var cookie2 = + { + name: 'test-cookie2', + value: 'test-value2', + maxAge: -1, + secure: false, + path: '/' + }; + var request = http.createRequest({ + method: 'GET', + path: '/' + }); + request.addCookie(cookie1); + request.addCookie(cookie2); + forge.log.debug(cat, 'request', request.toString()); + } + + function response_get_cookies() + { + var response = http.createResponse(); + response.appendField('Set-Cookie', + 'test-cookie1=test-value1; max-age=0; path=/; secure'); + response.appendField('Set-Cookie', + 'test-cookie2=test-value2; ' + + 'expires=Thu, 21-Aug-2008 23:47:25 GMT; path=/'); + var cookies = response.getCookies(); + forge.log.debug(cat, 'cookies', cookies); + } + + //]]> + </script> + </head> + <body> + <div class="nav"><a href="index.html">Forge Tests</a> / HTTP</div> + + <div class="header"> + <h1>HTTP Test</h1> + </div> + + <div class="content"> + + <div id="socketPool"> + <p>Could not load the flash SocketPool.</p> + </div> + + <fieldset class="section"> + <ul> + <li>Use the controls below to test the HTTP client.</li> + <li>You currently need a JavaScript console to view the output.</li> + </ul> + </fieldset> + + <fieldset class="section"> + <legend>Controls</legend> + <button id="init" onclick="javascript:return client_init();">init</button> + <button id="cleanup" onclick="javascript:return client_cleanup();">cleanup</button> + <button id="send" onclick="javascript:return client_send();">send</button> + <button id="send10" onclick="javascript:return client_send_10();">send 10</button> + <button id="stress" onclick="javascript:return client_stress();">stress</button> + <button id="client_cookies" onclick="javascript:return client_cookies();">cookies</button> + <button id="clear_cookies" onclick="javascript:return client_clear_cookies();">clear cookies</button> + <button id="add_cookies" onclick="javascript:return request_add_cookies();">add cookies</button> + <button id="get_cookies" onclick="javascript:return response_get_cookies();">get cookies</button> + </fieldset> + + <fieldset class="section"> + <legend>Feedback</legend> + <p>Feedback from the flash SocketPool:</p> + <div id="feedback"> + None + </div> + + </div> + </body> +</html> diff --git a/school/node_modules/node-forge/tests/index.html b/school/node_modules/node-forge/tests/index.html new file mode 100644 index 0000000..2e27c8a --- /dev/null +++ b/school/node_modules/node-forge/tests/index.html @@ -0,0 +1,64 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> + +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> + <meta name="author" content="Digital Bazaar, Inc.; http://digitalbazaar.com/" /> + <meta name="description" content="Forge Tests" /> + <link type="text/css" rel="stylesheet" media="all" href="screen.css" /> + <title>Forge Tests</title> +</head> + +<body> + <div class="header"> + <h1>Forge Tests</h1> + </div> + <div class="content"> + <fieldset class="section"> + <ul> + <li>These are various tests of the Forge JavaScript libraries.</li> + <li>Please see the code and documentation for details.</li> + </ul> + </fieldset> + <fieldset class="section"> + <legend>Tests</legend> + <ul> + <li><a href="common.html">Common</a> + <sup>1,2</sup> + </li> + <li><a href="form.html">Form</a> + <sup>1,2</sup> + </li> + <li><a href="performance.html">Performance</a> + <sup>1,2</sup> + </li> + <li><a href="tasks.html">Tasks</a> + <sup>1,2</sup> + </li> + <li><a href="socketPool.html">SocketPool</a> + <sup>1</sup> + </li> + <li><a href="http.html">HTTP</a> + <sup>1</sup> + </li> + <li><a href="tls.html">TLS</a> + <sup>2</sup> + </li> + <li><a href="xhr.html">XHR</a> + <sup>1,2</sup> + </li> + <li><a href="webid.html">Web ID</a> + <sup>1,2</sup> + </li> + </ul> + <div> + <span><sup>1</sup>: Test works over HTTP</span><br/> + <span><sup>2</sup>: Test works over HTTPS</span> + </div> + </fieldset> + </div> + <div class="footer"> + Copyright © 2010 <a href="http://digitalbazaar.com/">Digital Bazaar, Inc.</a> + </div> +</body> +</html> diff --git a/school/node_modules/node-forge/tests/keygen.html b/school/node_modules/node-forge/tests/keygen.html new file mode 100644 index 0000000..22e2432 --- /dev/null +++ b/school/node_modules/node-forge/tests/keygen.html @@ -0,0 +1,56 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="utf-8" /> + <script type="text/javascript" src="forge/util.js"></script> + <script type="text/javascript" src="forge/sha256.js"></script> + <script type="text/javascript" src="forge/cipher.js"></script> + <script type="text/javascript" src="forge/cipherModes.js"></script> + <script type="text/javascript" src="forge/aes.js"></script> + <script type="text/javascript" src="forge/prng.js"></script> + <script type="text/javascript" src="forge/random.js"></script> + <script type="text/javascript" src="forge/jsbn.js"></script> + <script type="text/javascript" src="forge/asn1.js"></script> + <script type="text/javascript" src="forge/pem.js"></script> + <script type="text/javascript" src="forge/rsa.js"></script> +</head> + +<body> + +<script type="text/javascript"> + +function async() { + var bits = 2048; + console.log('Generating ' + bits + '-bit key-pair...'); + var st = +new Date(); + forge.pki.rsa.generateKeyPair({ + bits: bits, + workers: -1, + /*workLoad: 100,*/ + workerScript: 'forge/prime.worker.js' + }, function(err, keypair) { + var et = +new Date(); + console.log('Key-pair created in ' + (et - st) + 'ms.'); + //console.log('private', forge.pki.privateKeyToPem(keypair.privateKey)); + //console.log('public', forge.pki.publicKeyToPem(keypair.publicKey)); + }); +} + +function sync() { + var bits = 2048; + console.log('Generating ' + bits + '-bit key-pair...'); + var st = +new Date(); + var keypair = forge.pki.rsa.generateKeyPair(bits); + var et = +new Date(); + console.log('Key-pair created in ' + (et - st) + 'ms.'); + //console.log('private', forge.pki.privateKeyToPem(keypair.privateKey)); + //console.log('public', forge.pki.publicKeyToPem(keypair.publicKey)); +} + +async(); +//sync(); + +</script> + +</body> +</html> diff --git a/school/node_modules/node-forge/tests/login.css b/school/node_modules/node-forge/tests/login.css new file mode 100644 index 0000000..3a1cb05 --- /dev/null +++ b/school/node_modules/node-forge/tests/login.css @@ -0,0 +1,26 @@ +/* WebID CSS */ + +* { +margin: 0; +padding: 0; +} + +p { +margin: 10px 0; +} + +body { +margin: 10px; +font-family: helvetica,arial,sans-serif; +font-size: 14px; +} + +#header { +padding: 5px; +background-color: #ddf; +border: 2px solid #000; +} + +#header h1 { +font-size: 20px; +} diff --git a/school/node_modules/node-forge/tests/loginDemo.html b/school/node_modules/node-forge/tests/loginDemo.html new file mode 100644 index 0000000..a1aecd4 --- /dev/null +++ b/school/node_modules/node-forge/tests/loginDemo.html @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head> + <title>Web ID Login</title> + <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js"></script> + <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script> + <script type="text/javascript" src="forge/debug.js"></script> + <script type="text/javascript" src="forge/util.js"></script> + <script type="text/javascript" src="forge/log.js"></script> + <script type="text/javascript" src="forge/task.js"></script> + <script type="text/javascript" src="forge/socket.js"></script> + <script type="text/javascript" src="forge/md5.js"></script> + <script type="text/javascript" src="forge/sha1.js"></script> + <script type="text/javascript" src="forge/hmac.js"></script> + <script type="text/javascript" src="forge/aes.js"></script> + <script type="text/javascript" src="forge/pem.js"></script> + <script type="text/javascript" src="forge/asn1.js"></script> + <script type="text/javascript" src="forge/jsbn.js"></script> + <script type="text/javascript" src="forge/prng.js"></script> + <script type="text/javascript" src="forge/random.js"></script> + <script type="text/javascript" src="forge/oids.js"></script> + <script type="text/javascript" src="forge/rsa.js"></script> + <script type="text/javascript" src="forge/pbe.js"></script> + <script type="text/javascript" src="forge/x509.js"></script> + <script type="text/javascript" src="forge/pki.js"></script> + <script type="text/javascript" src="forge/tls.js"></script> + <script type="text/javascript" src="forge/aesCipherSuites.js"></script> + <script type="text/javascript" src="forge/http.js"></script> + <script type="text/javascript" src="forge/xhr.js"></script> + <script type="text/javascript" src="loginDemo.js"></script> + + <link type="text/css" rel="stylesheet" media="all" href="login.css" /> + </head> +<body> + +<div id="header"> + <h1>Web ID Login</h1> +</div> + +<div id="content"> + <p>Please select a Web ID to log in to <span id="domain">this website</span>.</p> + + <div id="webids"></div> + + <p>Do not select an identity if you do not trust this website.</p> + + <!-- div used to hold the flash socket pool implementation --> + <div id="socketPool"> + <p>Could not load the flash SocketPool.</p> + </div> +</div> + +</body> +</html> diff --git a/school/node_modules/node-forge/tests/loginDemo.js b/school/node_modules/node-forge/tests/loginDemo.js new file mode 100644 index 0000000..859e1f0 --- /dev/null +++ b/school/node_modules/node-forge/tests/loginDemo.js @@ -0,0 +1,149 @@ +/** + * Forge Web ID Tests + * + * @author Dave Longley + * + * Copyright (c) 2010 Digital Bazaar, Inc. All rights reserved. + */ +(function($) +{ + // load flash socket pool + window.forge.socketPool = {}; + window.forge.socketPool.ready = function() + { + // init page + init($); + }; + swfobject.embedSWF( + 'forge/SocketPool.swf', 'socketPool', '0', '0', '9.0.0', + false, {}, {allowscriptaccess: 'always'}, {}); +})(jQuery); + +var init = function($) +{ + // logging category + var cat = 'forge.tests.loginDemo'; + + // local alias + var forge = window.forge; + try + { + // get query variables + var query = forge.util.getQueryVariables(); + var domain = query.domain || ''; + var auth = query.auth || ''; + var redirect = query.redirect || ''; + var pport = query.pport || 843; + redirect = 'https://' + domain + '/' + redirect; + if(domain) + { + $('#domain').html('`' + domain + '`'); + } + + // for chosen webid + var chosen = null; + + // init forge xhr + forge.xhr.init({ + flashId: 'socketPool', + msie: $.browser.msie, + url: 'https://' + domain, + policyPort: pport, + connections: 1, + caCerts: [], + verify: function(c, verified, depth, certs) + { + // don't care about cert verification for test + return true; + }, + getCertificate: function(c) + { + forge.log.debug(cat, 'using cert', chosen.certificate); + return chosen.certificate; + }, + getPrivateKey: function(c) + { + //forge.log.debug(cat, 'using private key', chosen.privateKey); + return chosen.privateKey; + } + }); + + // get flash API + var flashApi = document.getElementById('socketPool'); + + // get web ids collection + var webids = forge.util.getItem( + flashApi, 'forge.test.webid', 'webids'); + webids = webids || {}; + + var id = 0; + var list = $('<ul/>'); + for(var key in webids) + { + (function(webid) + { + var cert = forge.pki.certificateFromPem(webid.certificate); + var item = $('<li/>'); + var button = $('<button>'); + button.attr('id', '' + (webid + id++)); + button.html('Choose'); + button.click(function() + { + button.attr('disabled', 'disabled'); + + // set chosen webid + chosen = webid; + + // do webid call + $.ajax( + { + type: 'GET', + url: '/' + auth, + success: function(data, textStatus, xhr) + { + if(data !== '') + { + forge.log.debug(cat, 'authentication completed'); + forge.log.debug(cat, data); + window.name = data; + } + else + { + forge.log.debug(cat, 'authentication failed'); + window.name = ''; + } + window.location = redirect; + }, + error: function(xhr, textStatus, errorThrown) + { + forge.log.error(cat, 'authentication failed'); + }, + xhr: forge.xhr.create + }); + }); + item.append(button); + item.append(' ' + key + '<br/>'); + + // display certificate attributes + var attr; + for(var n = 0; n < cert.subject.attributes.length; ++n) + { + attr = cert.subject.attributes[n]; + item.append(attr.name + ': ' + attr.value + '<br/>'); + } + + list.append(item); + })(webids[key]); + } + if(list.html() === '<ul/>') + { + list.append('None'); + } + + $('#webids').append(list); + } + catch(ex) + { + forge.log.error(cat, ex); + } +}; diff --git a/school/node_modules/node-forge/tests/nodejs-create-cert.js b/school/node_modules/node-forge/tests/nodejs-create-cert.js new file mode 100644 index 0000000..d1666eb --- /dev/null +++ b/school/node_modules/node-forge/tests/nodejs-create-cert.js @@ -0,0 +1,110 @@ +var forge = require('../js/forge'); + +console.log('Generating 1024-bit key-pair...'); +var keys = forge.pki.rsa.generateKeyPair(1024); +console.log('Key-pair created.'); + +console.log('Creating self-signed certificate...'); +var cert = forge.pki.createCertificate(); +cert.publicKey = keys.publicKey; +cert.serialNumber = '01'; +cert.validity.notBefore = new Date(); +cert.validity.notAfter = new Date(); +cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 1); +var attrs = [{ + name: 'commonName', + value: 'example.org' +}, { + name: 'countryName', + value: 'US' +}, { + shortName: 'ST', + value: 'Virginia' +}, { + name: 'localityName', + value: 'Blacksburg' +}, { + name: 'organizationName', + value: 'Test' +}, { + shortName: 'OU', + value: 'Test' +}]; +cert.setSubject(attrs); +cert.setIssuer(attrs); +cert.setExtensions([{ + name: 'basicConstraints', + cA: true/*, + pathLenConstraint: 4*/ +}, { + name: 'keyUsage', + keyCertSign: true, + digitalSignature: true, + nonRepudiation: true, + keyEncipherment: true, + dataEncipherment: true +}, { + name: 'extKeyUsage', + serverAuth: true, + clientAuth: true, + codeSigning: true, + emailProtection: true, + timeStamping: true +}, { + name: 'nsCertType', + client: true, + server: true, + email: true, + objsign: true, + sslCA: true, + emailCA: true, + objCA: true +}, { + name: 'subjectAltName', + altNames: [{ + type: 6, // URI + value: 'http://example.org/webid#me' + }, { + type: 7, // IP + ip: '127.0.0.1' + }] +}, { + name: 'subjectKeyIdentifier' +}]); +// FIXME: add authorityKeyIdentifier extension + +// self-sign certificate +cert.sign(keys.privateKey/*, forge.md.sha256.create()*/); +console.log('Certificate created.'); + +// PEM-format keys and cert +var pem = { + privateKey: forge.pki.privateKeyToPem(keys.privateKey), + publicKey: forge.pki.publicKeyToPem(keys.publicKey), + certificate: forge.pki.certificateToPem(cert) +}; + +console.log('\nKey-Pair:'); +console.log(pem.privateKey); +console.log(pem.publicKey); + +console.log('\nCertificate:'); +console.log(pem.certificate); + +// verify certificate +var caStore = forge.pki.createCaStore(); +caStore.addCertificate(cert); +try { + forge.pki.verifyCertificateChain(caStore, [cert], + function(vfd, depth, chain) { + if(vfd === true) { + console.log('SubjectKeyIdentifier verified: ' + + cert.verifySubjectKeyIdentifier()); + console.log('Certificate verified.'); + } + return true; + }); +} catch(ex) { + console.log('Certificate verification failure: ' + + JSON.stringify(ex, null, 2)); +} diff --git a/school/node_modules/node-forge/tests/nodejs-create-csr.js b/school/node_modules/node-forge/tests/nodejs-create-csr.js new file mode 100644 index 0000000..1cb335f --- /dev/null +++ b/school/node_modules/node-forge/tests/nodejs-create-csr.js @@ -0,0 +1,66 @@ +var forge = require('../js/forge'); + +console.log('Generating 1024-bit key-pair...'); +var keys = forge.pki.rsa.generateKeyPair(1024); +console.log('Key-pair created.'); + +console.log('Creating certification request (CSR) ...'); +var csr = forge.pki.createCertificationRequest(); +csr.publicKey = keys.publicKey; +csr.setSubject([{ + name: 'commonName', + value: 'example.org' +}, { + name: 'countryName', + value: 'US' +}, { + shortName: 'ST', + value: 'Virginia' +}, { + name: 'localityName', + value: 'Blacksburg' +}, { + name: 'organizationName', + value: 'Test' +}, { + shortName: 'OU', + value: 'Test' +}]); +// add optional attributes +csr.setAttributes([{ + name: 'challengePassword', + value: 'password' +}, { + name: 'unstructuredName', + value: 'My company' +}]); + +// sign certification request +csr.sign(keys.privateKey/*, forge.md.sha256.create()*/); +console.log('Certification request (CSR) created.'); + +// PEM-format keys and csr +var pem = { + privateKey: forge.pki.privateKeyToPem(keys.privateKey), + publicKey: forge.pki.publicKeyToPem(keys.publicKey), + csr: forge.pki.certificationRequestToPem(csr) +}; + +console.log('\nKey-Pair:'); +console.log(pem.privateKey); +console.log(pem.publicKey); + +console.log('\nCertification Request (CSR):'); +console.log(pem.csr); + +// verify certification request +try { + if(csr.verify()) { + console.log('Certification request (CSR) verified.'); + } else { + throw new Error('Signature not verified.'); + } +} catch(err) { + console.log('Certification request (CSR) verification failure: ' + + JSON.stringify(err, null, 2)); +} diff --git a/school/node_modules/node-forge/tests/nodejs-create-pkcs12.js b/school/node_modules/node-forge/tests/nodejs-create-pkcs12.js new file mode 100644 index 0000000..e52eefa --- /dev/null +++ b/school/node_modules/node-forge/tests/nodejs-create-pkcs12.js @@ -0,0 +1,160 @@ +var forge = require('../js/forge'); + +try { + // generate a keypair + console.log('Generating 1024-bit key-pair...'); + var keys = forge.pki.rsa.generateKeyPair(1024); + console.log('Key-pair created.'); + + // create a certificate + console.log('Creating self-signed certificate...'); + var cert = forge.pki.createCertificate(); + cert.publicKey = keys.publicKey; + cert.serialNumber = '01'; + cert.validity.notBefore = new Date(); + cert.validity.notAfter = new Date(); + cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 1); + var attrs = [{ + name: 'commonName', + value: 'example.org' + }, { + name: 'countryName', + value: 'US' + }, { + shortName: 'ST', + value: 'Virginia' + }, { + name: 'localityName', + value: 'Blacksburg' + }, { + name: 'organizationName', + value: 'Test' + }, { + shortName: 'OU', + value: 'Test' + }]; + cert.setSubject(attrs); + cert.setIssuer(attrs); + cert.setExtensions([{ + name: 'basicConstraints', + cA: true + }, { + name: 'keyUsage', + keyCertSign: true, + digitalSignature: true, + nonRepudiation: true, + keyEncipherment: true, + dataEncipherment: true + }, { + name: 'subjectAltName', + altNames: [{ + type: 6, // URI + value: 'http://example.org/webid#me' + }] + }]); + + // self-sign certificate + cert.sign(keys.privateKey); + console.log('Certificate created.'); + + // create PKCS12 + console.log('\nCreating PKCS#12...'); + var password = 'password'; + var newPkcs12Asn1 = forge.pkcs12.toPkcs12Asn1( + keys.privateKey, [cert], password, + {generateLocalKeyId: true, friendlyName: 'test'}); + var newPkcs12Der = forge.asn1.toDer(newPkcs12Asn1).getBytes(); + + console.log('\nBase64-encoded new PKCS#12:'); + console.log(forge.util.encode64(newPkcs12Der)); + + // create CA store (w/own certificate in this example) + var caStore = forge.pki.createCaStore([cert]); + + console.log('\nLoading new PKCS#12 to confirm...'); + loadPkcs12(newPkcs12Der, password, caStore); +} catch(ex) { + if(ex.stack) { + console.log(ex.stack); + } else { + console.log('Error', ex); + } +} + +function loadPkcs12(pkcs12Der, password, caStore) { + var pkcs12Asn1 = forge.asn1.fromDer(pkcs12Der); + var pkcs12 = forge.pkcs12.pkcs12FromAsn1(pkcs12Asn1, false, password); + + // load keypair and cert chain from safe content(s) and map to key ID + var map = {}; + for(var sci = 0; sci < pkcs12.safeContents.length; ++sci) { + var safeContents = pkcs12.safeContents[sci]; + console.log('safeContents ' + (sci + 1)); + + for(var sbi = 0; sbi < safeContents.safeBags.length; ++sbi) { + var safeBag = safeContents.safeBags[sbi]; + console.log('safeBag.type: ' + safeBag.type); + + var localKeyId = null; + if(safeBag.attributes.localKeyId) { + localKeyId = forge.util.bytesToHex( + safeBag.attributes.localKeyId[0]); + console.log('localKeyId: ' + localKeyId); + if(!(localKeyId in map)) { + map[localKeyId] = { + privateKey: null, + certChain: [] + }; + } + } else { + // no local key ID, skip bag + continue; + } + + // this bag has a private key + if(safeBag.type === forge.pki.oids.pkcs8ShroudedKeyBag) { + console.log('found private key'); + map[localKeyId].privateKey = safeBag.key; + } else if(safeBag.type === forge.pki.oids.certBag) { + // this bag has a certificate + console.log('found certificate'); + map[localKeyId].certChain.push(safeBag.cert); + } + } + } + + console.log('\nPKCS#12 Info:'); + + for(var localKeyId in map) { + var entry = map[localKeyId]; + console.log('\nLocal Key ID: ' + localKeyId); + if(entry.privateKey) { + var privateKeyP12Pem = forge.pki.privateKeyToPem(entry.privateKey); + var encryptedPrivateKeyP12Pem = forge.pki.encryptRsaPrivateKey( + entry.privateKey, password); + + console.log('\nPrivate Key:'); + console.log(privateKeyP12Pem); + console.log('Encrypted Private Key (password: "' + password + '"):'); + console.log(encryptedPrivateKeyP12Pem); + } else { + console.log(''); + } + if(entry.certChain.length > 0) { + console.log('Certificate chain:'); + var certChain = entry.certChain; + for(var i = 0; i < certChain.length; ++i) { + var certP12Pem = forge.pki.certificateToPem(certChain[i]); + console.log(certP12Pem); + } + + var chainVerified = false; + try { + chainVerified = forge.pki.verifyCertificateChain(caStore, certChain); + } catch(ex) { + chainVerified = ex; + } + console.log('Certificate chain verified: ', chainVerified); + } + } +} diff --git a/school/node_modules/node-forge/tests/nodejs-imap.js b/school/node_modules/node-forge/tests/nodejs-imap.js new file mode 100644 index 0000000..ba024ef --- /dev/null +++ b/school/node_modules/node-forge/tests/nodejs-imap.js @@ -0,0 +1,46 @@ +var forge = require('../js/forge'); +var net = require('net'); + +var socket = new net.Socket(); + +var client = forge.tls.createConnection({ + server: false, + verify: function(connection, verified, depth, certs) { + // skip verification for testing + return true; + }, + connected: function(connection) { + console.log('[tls] connected'); + }, + tlsDataReady: function(connection) { + // encrypted data is ready to be sent to the server + var data = connection.tlsData.getBytes(); + socket.write(data, 'binary'); + }, + dataReady: function(connection) { + // clear data from the server is ready + var data = connection.data.getBytes(); + console.log('[tls] received from the server: ' + data); + client.close(); + }, + closed: function() { + console.log('[tls] disconnected'); + }, + error: function(connection, error) { + console.log('[tls] error', error); + } +}); + +socket.on('connect', function() { + console.log('[socket] connected'); + client.handshake(); +}); +socket.on('data', function(data) { + client.process(data.toString('binary')); +}); +socket.on('end', function() { + console.log('[socket] disconnected'); +}); + +// connect to gmail's imap server +socket.connect(993, 'imap.gmail.com'); diff --git a/school/node_modules/node-forge/tests/nodejs-tls.js b/school/node_modules/node-forge/tests/nodejs-tls.js new file mode 100644 index 0000000..5be6acd --- /dev/null +++ b/school/node_modules/node-forge/tests/nodejs-tls.js @@ -0,0 +1,189 @@ +var forge = require('../js/forge'); + +// function to create certificate +var createCert = function(cn, data) { + console.log( + 'Generating 512-bit key-pair and certificate for \"' + cn + '\".'); + var keys = forge.pki.rsa.generateKeyPair(512); + console.log('key-pair created.'); + + var cert = forge.pki.createCertificate(); + cert.serialNumber = '01'; + cert.validity.notBefore = new Date(); + cert.validity.notAfter = new Date(); + cert.validity.notAfter.setFullYear( + cert.validity.notBefore.getFullYear() + 1); + var attrs = [{ + name: 'commonName', + value: cn + }, { + name: 'countryName', + value: 'US' + }, { + shortName: 'ST', + value: 'Virginia' + }, { + name: 'localityName', + value: 'Blacksburg' + }, { + name: 'organizationName', + value: 'Test' + }, { + shortName: 'OU', + value: 'Test' + }]; + cert.setSubject(attrs); + cert.setIssuer(attrs); + cert.setExtensions([{ + name: 'basicConstraints', + cA: true + }, { + name: 'keyUsage', + keyCertSign: true, + digitalSignature: true, + nonRepudiation: true, + keyEncipherment: true, + dataEncipherment: true + }, { + name: 'subjectAltName', + altNames: [{ + type: 6, // URI + value: 'http://myuri.com/webid#me' + }] + }]); + // FIXME: add subjectKeyIdentifier extension + // FIXME: add authorityKeyIdentifier extension + cert.publicKey = keys.publicKey; + + // self-sign certificate + cert.sign(keys.privateKey); + + // save data + data[cn] = { + cert: forge.pki.certificateToPem(cert), + privateKey: forge.pki.privateKeyToPem(keys.privateKey) + }; + + console.log('certificate created for \"' + cn + '\": \n' + data[cn].cert); +}; + +var end = {}; +var data = {}; + +// create certificate for server and client +createCert('server', data); +createCert('client', data); + +var success = false; + +// create TLS client +end.client = forge.tls.createConnection({ + server: false, + caStore: [data.server.cert], + sessionCache: {}, + // supported cipher suites in order of preference + cipherSuites: [ + forge.tls.CipherSuites.TLS_RSA_WITH_AES_128_CBC_SHA, + forge.tls.CipherSuites.TLS_RSA_WITH_AES_256_CBC_SHA], + virtualHost: 'server', + verify: function(c, verified, depth, certs) { + console.log( + 'TLS Client verifying certificate w/CN: \"' + + certs[0].subject.getField('CN').value + + '\", verified: ' + verified + '...'); + return verified; + }, + connected: function(c) { + console.log('Client connected...'); + + // send message to server + setTimeout(function() { + c.prepareHeartbeatRequest('heartbeat'); + c.prepare('Hello Server'); + }, 1); + }, + getCertificate: function(c, hint) { + console.log('Client getting certificate ...'); + return data.client.cert; + }, + getPrivateKey: function(c, cert) { + return data.client.privateKey; + }, + tlsDataReady: function(c) { + // send TLS data to server + end.server.process(c.tlsData.getBytes()); + }, + dataReady: function(c) { + var response = c.data.getBytes(); + console.log('Client received \"' + response + '\"'); + success = (response === 'Hello Client'); + c.close(); + }, + heartbeatReceived: function(c, payload) { + console.log('Client received heartbeat: ' + payload.getBytes()); + }, + closed: function(c) { + console.log('Client disconnected.'); + if(success) { + console.log('PASS'); + } else { + console.log('FAIL'); + } + }, + error: function(c, error) { + console.log('Client error: ' + error.message); + } +}); + +// create TLS server +end.server = forge.tls.createConnection({ + server: true, + caStore: [data.client.cert], + sessionCache: {}, + // supported cipher suites in order of preference + cipherSuites: [ + forge.tls.CipherSuites.TLS_RSA_WITH_AES_128_CBC_SHA, + forge.tls.CipherSuites.TLS_RSA_WITH_AES_256_CBC_SHA], + connected: function(c) { + console.log('Server connected'); + c.prepareHeartbeatRequest('heartbeat'); + }, + verifyClient: true, + verify: function(c, verified, depth, certs) { + console.log( + 'Server verifying certificate w/CN: \"' + + certs[0].subject.getField('CN').value + + '\", verified: ' + verified + '...'); + return verified; + }, + getCertificate: function(c, hint) { + console.log('Server getting certificate for \"' + hint[0] + '\"...'); + return data.server.cert; + }, + getPrivateKey: function(c, cert) { + return data.server.privateKey; + }, + tlsDataReady: function(c) { + // send TLS data to client + end.client.process(c.tlsData.getBytes()); + }, + dataReady: function(c) { + console.log('Server received \"' + c.data.getBytes() + '\"'); + + // send response + c.prepare('Hello Client'); + c.close(); + }, + heartbeatReceived: function(c, payload) { + console.log('Server received heartbeat: ' + payload.getBytes()); + }, + closed: function(c) { + console.log('Server disconnected.'); + }, + error: function(c, error) { + console.log('Server error: ' + error.message); + } +}); + +console.log('created TLS client and server, doing handshake...'); +end.client.handshake(); diff --git a/school/node_modules/node-forge/tests/nodejs-ws-webid.js b/school/node_modules/node-forge/tests/nodejs-ws-webid.js new file mode 100644 index 0000000..fae0b82 --- /dev/null +++ b/school/node_modules/node-forge/tests/nodejs-ws-webid.js @@ -0,0 +1,491 @@ +var forge = require('../js/forge'); +var fs = require('fs'); +var http = require('http'); +//var rdf = require('./rdflib'); +var sys = require('sys'); +var urllib = require('url'); +var ws = require('./ws'); + +// remove xmlns from input +var normalizeNs = function(input, ns) { + var rval = null; + + // primitive + if(typeof input === 'string' || + typeof input === 'number' || + typeof input === 'boolean') { + rval = input; + } + // array + else if(forge.util.isArray(input)) { + rval = []; + for(var i = 0; i < input.length; ++i) { + rval.push(normalizeNs(input[i], ns)); + } + } + // object + else { + if('@' in input) { + // copy namespace map + var newNs = {}; + for(var key in ns) { + newNs[key] = ns[key]; + } + ns = newNs; + + // update namespace map + for(var key in input['@']) { + if(key.indexOf('xmlns:') === 0) { + ns[key.substr(6)] = input['@'][key]; + } + } + } + + rval = {}; + for(var key in input) { + if(key.indexOf('xmlns:') !== 0) { + var value = input[key]; + var colon = key.indexOf(':'); + if(colon !== -1) { + var prefix = key.substr(0, colon); + if(prefix in ns) { + key = ns[prefix] + key.substr(colon + 1); + } + } + rval[key] = normalizeNs(value, ns); + } + } + } + + return rval; +}; + +// gets public key from WebID rdf +var getPublicKey = function(data, uri, callback) { + // FIXME: use RDF library to simplify code below + //var kb = new rdf.RDFParser(rdf.IndexedFormula(), uri).loadBuf(data); + //var CERT = rdf.Namespace('http://www.w3.org/ns/auth/cert#'); + //var RSA = rdf.Namespace('http://www.w3.org/ns/auth/rsa#'); + var RDF = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'; + var CERT = 'http://www.w3.org/ns/auth/cert#'; + var RSA = 'http://www.w3.org/ns/auth/rsa#'; + var desc = RDF + 'Description'; + var about = RDF + 'about'; + var type = RDF + 'type'; + var resource = RDF + 'resource'; + var publicKey = RSA + 'RSAPublicKey'; + var modulus = RSA + 'modulus'; + var exponent = RSA + 'public_exponent'; + var identity = CERT + 'identity'; + var hex = CERT + 'hex'; + var decimal = CERT + 'decimal'; + + // gets a resource identifer from a node + var getResource = function(node, key) { + var rval = null; + + // special case 'about' + if(key === about) { + if('@' in node && about in node['@']) { + rval = node['@'][about]; + } + } + // any other resource + else if( + key in node && + typeof node[key] === 'object' && !forge.util.isArray(node[key]) && + '@' in node[key] && resource in node[key]['@']) { + rval = node[key]['@'][resource]; + } + + return rval; + }; + + // parse XML + uri = urllib.parse(uri); + var xml2js = require('./xml2js'); + var parser = new xml2js.Parser(); + parser.addListener('end', function(result) { + // normalize namespaces + result = normalizeNs(result, {}); + + // find grab all public keys whose identity matches hash from uri + var keys = []; + if(desc in result) { + // normalize RDF descriptions to array + if(!forge.util.isArray(result[desc])) { + desc = [result[desc]]; + } + else { + desc = result[desc]; + } + + // collect properties for all resources + var graph = {}; + for(var i = 0; i < desc.length; ++i) { + var node = desc[i]; + var res = {}; + for(var key in node) { + var obj = getResource(node, key); + res[key] = (obj === null) ? node[key] : obj; + } + graph[getResource(node, about) || ''] = res; + } + + // for every public key w/identity that matches the uri hash + // save the public key modulus and exponent + for(var r in graph) { + var props = graph[r]; + if(identity in props && + type in props && + props[type] === publicKey && + props[identity] === uri.hash && + modulus in props && + exponent in props && + props[modulus] in graph && + props[exponent] in graph && + hex in graph[props[modulus]] && + decimal in graph[props[exponent]]) { + keys.push({ + modulus: graph[props[modulus]][hex], + exponent: graph[props[exponent]][decimal] + }); + } + } + } + + sys.log('Public keys from RDF: ' + JSON.stringify(keys)); + callback(keys); + }); + parser.parseString(data); +}; + +// compares two public keys for equality +var comparePublicKeys = function(key1, key2) { + return key1.modulus === key2.modulus && key1.exponent === key2.exponent; +}; + +// gets the RDF data from a URL +var fetchUrl = function(url, callback, redirects) { + // allow 3 redirects by default + if(typeof(redirects) === 'undefined') { + redirects = 3; + } + + sys.log('Fetching URL: \"' + url + '\"'); + + // parse URL + url = forge.util.parseUrl(url); + var client = http.createClient( + url.port, url.fullHost, url.scheme === 'https'); + var request = client.request('GET', url.path, { + 'Host': url.host, + 'Accept': 'application/rdf+xml' + }); + request.addListener('response', function(response) { + var body = ''; + + // error, return empty body + if(response.statusCode >= 400) { + callback(body); + } + // follow redirect + else if(response.statusCode === 302) { + if(redirects > 0) { + // follow redirect + fetchUrl(response.headers.location, callback, --redirects); + } + else { + // return empty body + callback(body); + } + } + // handle data + else { + response.setEncoding('utf8'); + response.addListener('data', function(chunk) { + body += chunk; + }); + response.addListener('end', function() { + callback(body); + }); + } + }); + request.end(); +}; + +// does WebID authentication +var authenticateWebId = function(c, state) { + var auth = false; + + // get client-certificate + var cert = c.peerCertificate; + + // get public key from certificate + var publicKey = { + modulus: cert.publicKey.n.toString(16).toLowerCase(), + exponent: cert.publicKey.e.toString(10) + }; + + sys.log( + 'Server verifying certificate w/CN: \"' + + cert.subject.getField('CN').value + '\"\n' + + 'Public Key: ' + JSON.stringify(publicKey)); + + // build queue of subject alternative names to authenticate with + var altNames = []; + var ext = cert.getExtension({name: 'subjectAltName'}); + if(ext !== null && ext.altNames) { + for(var i = 0; i < ext.altNames.length; ++i) { + var altName = ext.altNames[i]; + if(altName.type === 6) { + altNames.push(altName.value); + } + } + } + + // create authentication processor + var authNext = function() { + if(!auth) { + // no more alt names, auth failed + if(altNames.length === 0) { + sys.log('WebID authentication FAILED.'); + c.prepare(JSON.stringify({ + success: false, + error: 'Not Authenticated' + })); + c.close(); + } + // try next alt name + else { + // fetch URL + var url = altNames.shift(); + fetchUrl(url, function(body) { + // get public key + getPublicKey(body, url, function(keys) { + // compare public keys from RDF until one matches + for(var i = 0; !auth && i < keys.length; ++i) { + auth = comparePublicKeys(keys[i], publicKey); + } + if(auth) { + // send authenticated notice to client + sys.log('WebID authentication PASSED.'); + state.authenticated = true; + c.prepare(JSON.stringify({ + success: true, + cert: forge.pki.certificateToPem(cert), + webID: url, + rdf: forge.util.encode64(body) + })); + } + else { + // try next alt name + authNext(); + } + }); + }); + } + } + }; + + // do auth + authNext(); +}; + +// creates credentials (private key + certificate) +var createCredentials = function(cn, credentials) { + sys.log('Generating 512-bit key-pair and certificate for \"' + cn + '\".'); + var keys = forge.pki.rsa.generateKeyPair(512); + sys.log('key-pair created.'); + + var cert = forge.pki.createCertificate(); + cert.serialNumber = '01'; + cert.validity.notBefore = new Date(); + cert.validity.notAfter = new Date(); + cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 1); + var attrs = [{ + name: 'commonName', + value: cn + }, { + name: 'countryName', + value: 'US' + }, { + shortName: 'ST', + value: 'Virginia' + }, { + name: 'localityName', + value: 'Blacksburg' + }, { + name: 'organizationName', + value: 'Test' + }, { + shortName: 'OU', + value: 'Test' + }]; + cert.setSubject(attrs); + cert.setIssuer(attrs); + cert.setExtensions([{ + name: 'basicConstraints', + cA: true + }, { + name: 'keyUsage', + keyCertSign: true, + digitalSignature: true, + nonRepudiation: true, + keyEncipherment: true, + dataEncipherment: true + }, { + name: 'subjectAltName', + altNames: [{ + type: 6, // URI + value: 'http://myuri.com/webid#me' + }] + }]); + // FIXME: add subjectKeyIdentifier extension + // FIXME: add authorityKeyIdentifier extension + cert.publicKey = keys.publicKey; + + // self-sign certificate + cert.sign(keys.privateKey); + + // save credentials + credentials.key = forge.pki.privateKeyToPem(keys.privateKey); + credentials.cert = forge.pki.certificateToPem(cert); + + sys.log('Certificate created for \"' + cn + '\": \n' + credentials.cert); +}; + +// initialize credentials +var credentials = { + key: null, + cert: null +}; + +// read private key from file +var readPrivateKey = function(filename) { + credentials.key = fs.readFileSync(filename); + // try to parse from PEM as test + forge.pki.privateKeyFromPem(credentials.key); +}; + +// read certificate from file +var readCertificate = function(filename) { + credentials.cert = fs.readFileSync(filename); + // try to parse from PEM as test + forge.pki.certificateFromPem(credentials.cert); +}; + +// parse command line options +var opts = require('opts'); +var options = [ +{ short : 'v' +, long : 'version' +, description : 'Show version and exit' +, callback : function() { console.log('v1.0'); process.exit(1); } +}, +{ short : 'p' +, long : 'port' +, description : 'The port to listen for WebSocket connections on' +, value : true +}, +{ long : 'key' +, description : 'The server private key file to use in PEM format' +, value : true +, callback : readPrivateKey +}, +{ long : 'cert' +, description : 'The server certificate file to use in PEM format' +, value : true +, callback : readCertificate +} +]; +opts.parse(options, true); + +// create credentials for server +if(credentials.key === null || credentials.cert === null) { + createCredentials('server', credentials); +} + +// function to create TLS server connection +var createTls = function(websocket) { + var state = { + authenticated: false + }; + return forge.tls.createConnection({ + server: true, + caStore: [], + sessionCache: {}, + // supported cipher suites in order of preference + cipherSuites: [ + forge.tls.CipherSuites.TLS_RSA_WITH_AES_128_CBC_SHA, + forge.tls.CipherSuites.TLS_RSA_WITH_AES_256_CBC_SHA], + connected: function(c) { + sys.log('Server connected'); + + // do WebID authentication + try { + authenticateWebId(c, state); + } + catch(ex) { + c.close(); + } + }, + verifyClient: true, + verify: function(c, verified, depth, certs) { + // accept certs w/unknown-CA (48) + if(verified === 48) { + verified = true; + } + return verified; + }, + getCertificate: function(c, hint) { + sys.log('Server using certificate for \"' + hint[0] + '\"'); + return credentials.cert; + }, + getPrivateKey: function(c, cert) { + return credentials.key; + }, + tlsDataReady: function(c) { + // send base64-encoded TLS data over websocket + websocket.write(forge.util.encode64(c.tlsData.getBytes())); + }, + dataReady: function(c) { + // ignore any data until connection is authenticated + if(state.authenticated) { + sys.log('Server received \"' + c.data.getBytes() + '\"'); + } + }, + closed: function(c) { + sys.log('Server disconnected'); + websocket.end(); + }, + error: function(c, error) { + sys.log('Server error: ' + error.message); + } + }); +}; + +// create websocket server +var port = opts.get('port') || 8080; +ws.createServer(function(websocket) { + // create TLS server connection + var tls = createTls(websocket); + + websocket.addListener('connect', function(resource) { + sys.log('WebSocket connected: ' + resource); + + // close connection after 30 second timeout + setTimeout(websocket.end, 30 * 1000); + }); + + websocket.addListener('data', function(data) { + // base64-decode data and process it + tls.process(forge.util.decode64(data)); + }); + + websocket.addListener('close', function() { + sys.log('WebSocket closed'); + }); +}).listen(port); + +sys.log('WebSocket WebID server running on port ' + port); diff --git a/school/node_modules/node-forge/tests/nodejs-ws.js b/school/node_modules/node-forge/tests/nodejs-ws.js new file mode 100644 index 0000000..164962d --- /dev/null +++ b/school/node_modules/node-forge/tests/nodejs-ws.js @@ -0,0 +1,166 @@ +var sys = require('sys'); +var ws = require('./ws'); +var forge = require('../js/forge'); + +// function to create certificate +var createCert = function(cn, data) +{ + sys.puts( + 'Generating 512-bit key-pair and certificate for \"' + cn + '\".'); + var keys = forge.pki.rsa.generateKeyPair(512); + sys.puts('key-pair created.'); + + var cert = forge.pki.createCertificate(); + cert.serialNumber = '01'; + cert.validity.notBefore = new Date(); + cert.validity.notAfter = new Date(); + cert.validity.notAfter.setFullYear( + cert.validity.notBefore.getFullYear() + 1); + var attrs = [{ + name: 'commonName', + value: cn + }, { + name: 'countryName', + value: 'US' + }, { + shortName: 'ST', + value: 'Virginia' + }, { + name: 'localityName', + value: 'Blacksburg' + }, { + name: 'organizationName', + value: 'Test' + }, { + shortName: 'OU', + value: 'Test' + }]; + cert.setSubject(attrs); + cert.setIssuer(attrs); + cert.setExtensions([{ + name: 'basicConstraints', + cA: true + }, { + name: 'keyUsage', + keyCertSign: true, + digitalSignature: true, + nonRepudiation: true, + keyEncipherment: true, + dataEncipherment: true + }, { + name: 'subjectAltName', + altNames: [{ + type: 6, // URI + value: 'http://myuri.com/webid#me' + }] + }]); + // FIXME: add subjectKeyIdentifier extension + // FIXME: add authorityKeyIdentifier extension + cert.publicKey = keys.publicKey; + + // self-sign certificate + cert.sign(keys.privateKey); + + // save data + data[cn] = { + cert: forge.pki.certificateToPem(cert), + privateKey: forge.pki.privateKeyToPem(keys.privateKey) + }; + + sys.puts('certificate created for \"' + cn + '\": \n' + data[cn].cert); +}; + +var data = {}; + +// create certificate for server +createCert('server', data); + +// function to create TLS server connection +var createTls = function(websocket) +{ + return forge.tls.createConnection( + { + server: true, + caStore: [], + sessionCache: {}, + // supported cipher suites in order of preference + cipherSuites: [ + forge.tls.CipherSuites.TLS_RSA_WITH_AES_128_CBC_SHA, + forge.tls.CipherSuites.TLS_RSA_WITH_AES_256_CBC_SHA], + connected: function(c) + { + sys.puts('Server connected'); + }, + verifyClient: true, + verify: function(c, verified, depth, certs) + { + sys.puts( + 'Server verifying certificate w/CN: \"' + + certs[0].subject.getField('CN').value + + '\", verified: ' + verified + '...'); + + // accept any certificate (could actually do WebID authorization from + // here within the protocol) + return true; + }, + getCertificate: function(c, hint) + { + sys.puts('Server getting certificate for \"' + hint[0] + '\"...'); + return data.server.cert; + }, + getPrivateKey: function(c, cert) + { + return data.server.privateKey; + }, + tlsDataReady: function(c) + { + // send base64-encoded TLS data over websocket + websocket.write(forge.util.encode64(c.tlsData.getBytes())); + }, + dataReady: function(c) + { + sys.puts('Server received \"' + c.data.getBytes() + '\"'); + + // send response + c.prepare('Hello Client'); + }, + closed: function(c) + { + sys.puts('Server disconnected.'); + websocket.end(); + }, + error: function(c, error) + { + sys.puts('Server error: ' + error.message); + } + }); +}; + +// create websocket server +var port = 8080; +ws.createServer(function(websocket) +{ + // create TLS server connection + var tls = createTls(websocket); + + websocket.addListener('connect', function(resource) + { + sys.puts('connected: ' + resource); + + // close connection after 10 seconds + setTimeout(websocket.end, 10 * 1000); + }); + + websocket.addListener('data', function(data) + { + // base64-decode data and process it + tls.process(forge.util.decode64(data)); + }); + + websocket.addListener('close', function() + { + sys.puts('closed'); + }); +}).listen(port); + +sys.puts('server running on port ' + port); diff --git a/school/node_modules/node-forge/tests/performance.html b/school/node_modules/node-forge/tests/performance.html new file mode 100644 index 0000000..9acbcc5 --- /dev/null +++ b/school/node_modules/node-forge/tests/performance.html @@ -0,0 +1,550 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head> + <title>Forge Performance Tests</title> + <link type="text/css" rel="stylesheet" media="all" href="screen.css" /> + <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script> + <script type="text/javascript" src="forge/debug.js"></script> + <script type="text/javascript" src="forge/util.js"></script> + <script type="text/javascript" src="forge/log.js"></script> + <script type="text/javascript" src="forge/task.js"></script> + <script type="text/javascript" src="forge/md5.js"></script> + <script type="text/javascript" src="forge/sha1.js"></script> + <script type="text/javascript" src="forge/sha256.js"></script> + <script type="text/javascript" src="forge/hmac.js"></script> + <script type="text/javascript" src="forge/aes.js"></script> + <script type="text/javascript" src="forge/pem.js"></script> + <script type="text/javascript" src="forge/asn1.js"></script> + <script type="text/javascript" src="forge/jsbn.js"></script> + <script type="text/javascript" src="forge/prng.js"></script> + <script type="text/javascript" src="forge/random.js"></script> + <script type="text/javascript" src="forge/oids.js"></script> + <script type="text/javascript" src="forge/rsa.js"></script> + <script type="text/javascript" src="forge/pbe.js"></script> + <script type="text/javascript" src="forge/x509.js"></script> + <script type="text/javascript" src="forge/pki.js"></script> + <script type="text/javascript" src="forge/tls.js"></script> + <script type="text/javascript" src="forge/aesCipherSuites.js"></script> + + <script type="text/javascript"> + //<![CDATA[ + // logging category + var cat = 'forge.tests.performance'; + + var test_random = function() + { + forge.log.debug(cat, 'painting canvas...'); + setTimeout(function() + { + var canvas = document.getElementById("canvas"); + var ctx = canvas.getContext("2d"); + var imgData = ctx.createImageData(canvas.width, canvas.height); + + // generate random bytes + var bytes = forge.random.getBytes(canvas.width * canvas.height * 3); + var n = 0; + for(var x = 0; x < imgData.width; x++) + { + for(var y = 0; y < imgData.height; y++) + { + // index of the pixel in the array + var idx = (x + y * imgData.width) * 4; + + // set values + imgData.data[idx + 0] = bytes.charCodeAt(n++); // Red + imgData.data[idx + 1] = bytes.charCodeAt(n++); // Green + imgData.data[idx + 2] = bytes.charCodeAt(n++); // Blue + imgData.data[idx + 3] = 255; // Alpha + } + } + + ctx.putImageData(imgData, 0, 0); + forge.log.debug(cat, 'done'); + }, 0); + }; + + var canvas_clear = function() + { + var canvas = document.getElementById("canvas"); + var ctx = canvas.getContext("2d"); + ctx.clearRect(0, 0, canvas.width, canvas.height); + }; + + var test_buffer_fill = function() + { + forge.log.debug(cat, + 'buffer fill optimized vs. slow running for about 5 seconds...'); + + setTimeout(function() + { + // run slow fill for 2.5 seconds + var st, et; + var b = ''; + var passed = 0; + while(passed < 2500) + { + st = +new Date(); + b += 'b'; + et = +new Date(); + passed += (et - st); + } + + // do optimized fill + var buf = forge.util.createBuffer(); + st = +new Date(); + buf.fillWithByte('b'.charCodeAt(0), b.length); + et = +new Date(); + + forge.log.debug(cat, 'fill times', (et - st) + ' < ' + passed); + }); + }; + + var test_buffer_xor = function() + { + forge.log.debug(cat, + 'buffer xor optimized vs. slow running for about 5 seconds...'); + + setTimeout(function() + { + // run slow xor for 2.5 seconds + var st, et; + var output = forge.util.createBuffer(); + var passed = 0; + while(passed < 2500) + { + st = +new Date(); + output.putByte(0x01 ^ 0x02); + et = +new Date(); + passed += (et - st); + } + + // do optimized xor + var count = output.length(); + var b1 = forge.util.createBuffer(); + b1.fillWithByte(0x01, count); + var b2 = forge.util.createBuffer(); + b2.fillWithByte(0x02, count); + + st = +new Date(); + output = forge.util.xorBytes(b1.getBytes(), b2.getBytes(), count); + et = +new Date(); + + forge.log.debug(cat, 'xor times', (et - st) + ' < ' + passed); + }); + }; + + // TODO: follow the same format as the hash tests + var test_base64_encode = function() + { + forge.log.debug(cat, 'base64 encode running for about 5 seconds...'); + + setTimeout(function() + { + // get starting time to make test run for only 5 seconds + var start = +new Date(); + + // build data to encode + var str = ''; + for(var i = 0; i < 100; i++) + { + str += '00010203050607080A0B0C0D0F1011121415161719'; + } + + // keep encoding for 5 seconds, keep track of total and count + var total = 0, count = 0, st, et; + var passed = 0; + while(passed < 5000) + { + st = +new Date(); + forge.util.encode64(str); + et = +new Date(); + ++count; + total += (et - st); + passed = +new Date() - start; + } + + total /= 1000; + var kb = 4200/1024; + forge.log.debug(cat, + 'encode:', (count*kb/total) + ' KiB/s'); + }); + }; + + // TODO: follow the same format as the hash tests + var test_base64_decode = function() + { + forge.log.debug(cat, 'base64 decode running for about 5 seconds...'); + + setTimeout(function() + { + // get starting time to make test run for only 5 seconds + var start = +new Date(); + + // build data to decode + var str = ''; + for(var i = 0; i < 100; i++) + { + str += + 'MDAwMTAyMDMwNTA2MDcwODBBMEIwQzBEMEYxMDExMTIxNDE1MTYxNzE5'; + } + + // keep encoding for 5 seconds, keep track of total and count + var total = 0, count = 0, st, et; + var passed = 0; + while(passed < 5000) + { + st = +new Date(); + forge.util.decode64(str); + et = +new Date(); + ++count; + total += (et - st); + passed = +new Date() - start; + } + + total /= 1000; + var kb = 5600/1024; + forge.log.debug(cat, + 'decode:', (count*kb/total) + ' KiB/s'); + }); + }; + + var test_md5 = function() + { + // create input data + var input = ['0123456789abcdef', '', '', '', '']; + for(var i = 0; i < 4; ++i) + { + input[1] += input[0]; + } + for(var i = 0; i < 4; ++i) + { + input[2] += input[1]; + } + for(var i = 0; i < 4; ++i) + { + input[3] += input[2]; + } + for(var i = 0; i < 8; ++i) + { + input[4] += input[3]; + } + + var md = forge.md.md5.create(); + + forge.log.debug(cat, 'md5 times in 1000s of bytes/sec processed:'); + + var st, et; + var output = + [' 16 bytes: ', + ' 64 bytes: ', + ' 256 bytes: ', + '1024 bytes: ', + '8192 bytes: ']; + var s = [16, 64, 256, 1024, 8192]; + var t = [0, 0, 0, 0, 0]; + for(var n = 0; n < 5; ++n) + { + var f = function(n) + { + setTimeout(function() + { + // run for 2 seconds each + var count = 0; + while(t[n] < 2000) + { + md.start(); + st = +new Date(); + md.update(input[n]); + md.digest(); + et = +new Date(); + t[n] = t[n] + (et - st); + ++count; + } + t[n] /= 1000; + forge.log.debug(cat, + output[n], (count*s[n]/t[n]/1000) + 'k/sec'); + }, 0); + }(n); + } + }; + + var test_sha1 = function() + { + // create input data + var input = ['0123456789abcdef', '', '', '', '']; + for(var i = 0; i < 4; ++i) + { + input[1] += input[0]; + } + for(var i = 0; i < 4; ++i) + { + input[2] += input[1]; + } + for(var i = 0; i < 4; ++i) + { + input[3] += input[2]; + } + for(var i = 0; i < 8; ++i) + { + input[4] += input[3]; + } + + var md = forge.md.sha1.create(); + + forge.log.debug(cat, 'sha-1 times in 1000s of bytes/sec processed:'); + + var st, et; + var output = + [' 16 bytes: ', + ' 64 bytes: ', + ' 256 bytes: ', + '1024 bytes: ', + '8192 bytes: ']; + var s = [16, 64, 256, 1024, 8192]; + var t = [0, 0, 0, 0, 0]; + for(var n = 0; n < 5; ++n) + { + var f = function(n) + { + setTimeout(function() + { + // run for 2 seconds each + var count = 0; + while(t[n] < 2000) + { + md.start(); + st = +new Date(); + md.update(input[n]); + md.digest(); + et = +new Date(); + t[n] = t[n] + (et - st); + ++count; + } + t[n] /= 1000; + forge.log.debug(cat, + output[n], (count*s[n]/t[n]/1000) + 'k/sec'); + }, 0); + }(n); + } + }; + + var test_sha256 = function() + { + // create input data + var input = ['0123456789abcdef', '', '', '', '']; + for(var i = 0; i < 4; ++i) + { + input[1] += input[0]; + } + for(var i = 0; i < 4; ++i) + { + input[2] += input[1]; + } + for(var i = 0; i < 4; ++i) + { + input[3] += input[2]; + } + for(var i = 0; i < 8; ++i) + { + input[4] += input[3]; + } + + var md = forge.md.sha256.create(); + + forge.log.debug(cat, 'sha-256 times in 1000s of bytes/sec processed:'); + + var st, et; + var output = + [' 16 bytes: ', + ' 64 bytes: ', + ' 256 bytes: ', + '1024 bytes: ', + '8192 bytes: ']; + var s = [16, 64, 256, 1024, 8192]; + var t = [0, 0, 0, 0, 0]; + for(var n = 0; n < 5; ++n) + { + var f = function(n) + { + setTimeout(function() + { + // run for 2 seconds each + var count = 0; + while(t[n] < 2000) + { + md.start(); + st = +new Date(); + md.update(input[n]); + md.digest(); + et = +new Date(); + t[n] = t[n] + (et - st); + ++count; + } + t[n] /= 1000; + forge.log.debug(cat, + output[n], (count*s[n]/t[n]/1000) + 'k/sec'); + }, 0); + }(n); + } + }; + + // TODO: follow the same format as the hash tests + var aes_128 = function() + { + forge.log.debug(cat, 'running AES-128 for 5 seconds...'); + + var block = []; + block.push(0x00112233); + block.push(0x44556677); + block.push(0x8899aabb); + block.push(0xccddeeff); + + var key = []; + key.push(0x00010203); + key.push(0x04050607); + key.push(0x08090a0b); + key.push(0x0c0d0e0f); + + setTimeout(function() + { + // run for 5 seconds + var start = +new Date(); + var now; + var totalEncrypt = 0; + var totalDecrypt = 0; + var count = 0; + var passed = 0; + while(passed < 5000) + { + var output = []; + var w = forge.aes._expandKey(key, false); + now = +new Date(); + forge.aes._updateBlock(w, block, output, false); + totalEncrypt += +new Date() - now; + + block = output; + output = []; + w = forge.aes._expandKey(key, true); + now = +new Date(); + forge.aes._updateBlock(w, block, output, true); + totalDecrypt += +new Date() - now; + + ++count; + passed = +new Date() - start; + } + + count = count * 16 / 1000; + totalEncrypt /= 1000; + totalDecrypt /= 1000; + forge.log.debug(cat, 'times in 1000s of bytes/sec processed.'); + forge.log.debug(cat, + 'encrypt: ' + (count*16 / totalEncrypt) + ' k/sec'); + forge.log.debug(cat, + 'decrypt: ' + (count*16 / totalDecrypt) + ' k/sec'); + }, 0); + }; + + // TODO: follow the same format as the hash tests + var aes_128_cbc = function() + { + forge.log.debug(cat, 'running AES-128 CBC for 5 seconds...'); + + var key = forge.random.getBytes(16); + var iv = forge.random.getBytes(16); + var plain = forge.random.getBytes(16); + + setTimeout(function() + { + // run for 5 seconds + var start = +new Date(); + var now; + var totalEncrypt = 0; + var totalDecrypt = 0; + var cipher; + var count = 0; + var passed = 0; + while(passed < 5000) + { + var input = forge.util.createBuffer(plain); + + // encrypt, only measuring update() and finish() + cipher = forge.aes.startEncrypting(key, iv); + now = +new Date(); + cipher.update(input); + cipher.finish(); + totalEncrypt += +new Date() - now; + + // decrypt, only measuring update() and finish() + var ct = cipher.output; + cipher = forge.aes.startDecrypting(key, iv); + now = +new Date(); + cipher.update(ct); + cipher.finish(); + totalDecrypt += +new Date() - now; + + ++count; + passed = +new Date() - start; + } + + // 32 bytes encrypted because of 16 bytes of padding + count = count * 32 / 1000; + totalEncrypt /= 1000; + totalDecrypt /= 1000; + forge.log.debug(cat, 'times in 1000s of bytes/sec processed.'); + forge.log.debug(cat, + 'encrypt: ' + (count / totalEncrypt) + ' k/sec'); + forge.log.debug(cat, + 'decrypt: ' + (count / totalDecrypt) + ' k/sec'); + }, 0); + }; + + //]]> + </script> + </head> + <body> + <div class="nav"><a href="index.html">Forge Tests</a> / Performance</div> + + <div class="header"> + <h1>Performance Tests</h1> + </div> + + <div class="content"> + + <fieldset class="section"> + <ul> + <li>Use the controls below to run Forge performance tests.</li> + <li>You currently need a JavaScript console to view the output.</li> + </ul> + </fieldset> + + <fieldset class="section"> + <legend>Tests</legend> + + <div id="random_controls"> + <button id="random" onclick="javascript:return test_random();">paint random</button> + <button id="clear" onclick="javascript:return canvas_clear();">clear</button> + </div> + <canvas id="canvas" width="100" height="100"></canvas> + <div id="buffer_controls"> + <button id="buffer_fill" onclick="javascript:return test_buffer_fill();">buffer fill</button> + <button id="buffer_xor" onclick="javascript:return test_buffer_xor();">buffer xor</button> + </div> + <div id="base64_controls"> + <button id="base64_encode" onclick="javascript:return test_base64_encode();">base64 encode</button> + <button id="base64_decode" onclick="javascript:return test_base64_decode();">base64 decode</button> + </div> + <div id="hash_controls"> + <button id="md5" onclick="javascript:return test_md5();">md5</button> + <button id="sha1" onclick="javascript:return test_sha1();">sha1</button> + <button id="sha256" onclick="javascript:return test_sha256();">sha256</button> + </div> + <div id="aes_controls"> + <button id="aes_128" onclick="javascript:return aes_128();">aes-128</button> + <button id="aes_128_cbc" onclick="javascript:return aes_128_cbc();">aes-128 cbc</button> + </div> + </fieldset> + </div> + </body> +</html> diff --git a/school/node_modules/node-forge/tests/policyserver.py b/school/node_modules/node-forge/tests/policyserver.py new file mode 100755 index 0000000..bda8afe --- /dev/null +++ b/school/node_modules/node-forge/tests/policyserver.py @@ -0,0 +1,112 @@ +#!/usr/bin/env python + +""" +Flash Socket Policy Server. + +- Starts Flash socket policy file server. +- Defaults to port 843. +- NOTE: Most operating systems require administrative privileges to use + ports under 1024. + + $ ./policyserver.py [options] +""" + +""" +Also consider Adobe's solutions: +http://www.adobe.com/devnet/flashplayer/articles/socket_policy_files.html +""" + +from multiprocessing import Process +from optparse import OptionParser +import SocketServer +import logging + +# Set address reuse for all TCPServers +SocketServer.TCPServer.allow_reuse_address = True + +# Static socket policy file string. +# NOTE: This format is very strict. Edit with care. +socket_policy_file = """\ +<?xml version="1.0"?>\ +<!DOCTYPE cross-domain-policy\ + SYSTEM "http://www.adobe.com/xml/dtds/cross-domain-policy.dtd">\ +<cross-domain-policy>\ +<allow-access-from domain="*" to-ports="*"/>\ +</cross-domain-policy>\0""" + + +class PolicyHandler(SocketServer.BaseRequestHandler): + """ + The RequestHandler class for our server. + + Returns a policy file when requested. + """ + + def handle(self): + """Send policy string if proper request string is received.""" + # get some data + # TODO: make this more robust (while loop, etc) + self.data = self.request.recv(1024).rstrip('\0') + logging.debug("%s wrote:%s" % (self.client_address[0], repr(self.data))) + # if policy file request, send the file. + if self.data == "<policy-file-request/>": + logging.info("Policy server request from %s." % (self.client_address[0])) + self.request.send(socket_policy_file) + else: + logging.info("Policy server received junk from %s: \"%s\"" % \ + (self.client_address[0], repr(self.data))) + + +class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer): + def serve_forever(self): + """Handle one request at a time until shutdown or keyboard interrupt.""" + try: + SocketServer.BaseServer.serve_forever(self) + except KeyboardInterrupt: + return + + +def main(): + """Run socket policy file servers.""" + usage = "Usage: %prog [options]" + parser = OptionParser(usage=usage) + parser.add_option("", "--host", dest="host", metavar="HOST", + default="localhost", help="bind to HOST") + parser.add_option("-p", "--port", dest="port", metavar="PORT", + default=843, type="int", help="serve on PORT") + parser.add_option("-d", "--debug", dest="debug", action="store_true", + default=False, help="debugging output") + parser.add_option("-v", "--verbose", dest="verbose", action="store_true", + default=False, help="verbose output") + (options, args) = parser.parse_args() + + # setup logging + if options.debug: + lvl = logging.DEBUG + elif options.verbose: + lvl = logging.INFO + else: + lvl = logging.WARNING + logging.basicConfig(level=lvl, format="%(levelname)-8s %(message)s") + + # log basic info + logging.info("Flash Socket Policy Server. Use ctrl-c to exit.") + + # create policy server + logging.info("Socket policy serving on %s:%d." % (options.host, options.port)) + policyd = ThreadedTCPServer((options.host, options.port), PolicyHandler) + + # start server + policy_p = Process(target=policyd.serve_forever) + policy_p.start() + + while policy_p.is_alive(): + try: + policy_p.join(1) + except KeyboardInterrupt: + logging.info("Stopping test server...") + + +if __name__ == "__main__": + main() + diff --git a/school/node_modules/node-forge/tests/result.txt b/school/node_modules/node-forge/tests/result.txt new file mode 100644 index 0000000..7cb007c --- /dev/null +++ b/school/node_modules/node-forge/tests/result.txt @@ -0,0 +1 @@ +expected result diff --git a/school/node_modules/node-forge/tests/screen.css b/school/node_modules/node-forge/tests/screen.css new file mode 100644 index 0000000..365a39f --- /dev/null +++ b/school/node_modules/node-forge/tests/screen.css @@ -0,0 +1,61 @@ +/* CSS for Forge tests */ +body { + background: white; + color: black; + margin: 0; + padding: 0; +} +.warning { + border: thin solid red; + background: #7FF; +} +div.nav { + background: white; + border-bottom: thin solid black; + padding: .5em; + padding-top: .2em; + padding-bottom: .2em; +} +div.header { + border-bottom: thin solid black; + padding: .5em; +} +div.content { + padding: .5em; + background: #DDD; +} +div.footer { + border-top: thin solid black; + font-size: 80%; + padding: .5em; +} +canvas { + background: black; +} +table, td, th { + border: thin solid black; + border-collapse: collapse; +} +td, th { + padding: .2em; +} +span.sp-state-on { + font-weight: bold; +} +table#feedback { + width: 100%; +} +table#feedback th, table#feedback td { + width: 33%; +} +fieldset.section { + margin: .5em; + border: 2px solid black; + background: #FFF; +} +fieldset.section legend { + padding: .2em; + border: 2px solid black; + background: #DDF; + font-weight: bold; +} diff --git a/school/node_modules/node-forge/tests/server.crt b/school/node_modules/node-forge/tests/server.crt new file mode 100644 index 0000000..6952426 --- /dev/null +++ b/school/node_modules/node-forge/tests/server.crt @@ -0,0 +1,26 @@ +-----BEGIN CERTIFICATE----- +MIIEaDCCA1CgAwIBAgIJAJuj0AjEWncuMA0GCSqGSIb3DQEBBQUAMH8xCzAJBgNV +BAYTAlVTMREwDwYDVQQIEwhWaXJnaW5pYTETMBEGA1UEBxMKQmxhY2tzYnVyZzEd +MBsGA1UEChMURGlnaXRhbCBCYXphYXIsIEluYy4xGjAYBgNVBAsTEUZvcmdlIFRl +c3QgU2VydmVyMQ0wCwYDVQQDEwR0ZXN0MB4XDTEwMDcxMzE3MjAzN1oXDTMwMDcw +ODE3MjAzN1owfzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMRMwEQYD +VQQHEwpCbGFja3NidXJnMR0wGwYDVQQKExREaWdpdGFsIEJhemFhciwgSW5jLjEa +MBgGA1UECxMRRm9yZ2UgVGVzdCBTZXJ2ZXIxDTALBgNVBAMTBHRlc3QwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCm/FobjqK8CVP/Xbnpyhf1tpoyaiFf +ShUOmlWqL5rLe0Q0dDR/Zur+sLMUv/1T4wOfFkjjxvZ0Sk5NIjK3Wy2UA41a+M3J +RTbCFrg4ujsovFaD4CDmV7Rek0qJB3m5Gp7hgu5vfL/v+WrwxnQObNq+IrTMSA15 +cO4LzNIPj9K1LN2dB+ucT7xTQFHAfvLLgLlCLiberoabF4rEhgTMTbmMtFVKSt+P +xgQIYPnhw1WuAvE9hFesRQFdfARLqIZk92FeHkgtHv9BAunktJemcidbowTCTBaM +/njcgi1Tei/LFkph/FCVyGER0pekJNHX626bAQSLo/srsWfmcll9rK6bAgMBAAGj +geYwgeMwHQYDVR0OBBYEFCau5k6jxezjULlLuo/liswJlBF8MIGzBgNVHSMEgasw +gaiAFCau5k6jxezjULlLuo/liswJlBF8oYGEpIGBMH8xCzAJBgNVBAYTAlVTMREw +DwYDVQQIEwhWaXJnaW5pYTETMBEGA1UEBxMKQmxhY2tzYnVyZzEdMBsGA1UEChMU +RGlnaXRhbCBCYXphYXIsIEluYy4xGjAYBgNVBAsTEUZvcmdlIFRlc3QgU2VydmVy +MQ0wCwYDVQQDEwR0ZXN0ggkAm6PQCMRady4wDAYDVR0TBAUwAwEB/zANBgkqhkiG +9w0BAQUFAAOCAQEAnP/2mzFWaoGx6+KAfY8pcgnF48IoyKPx5cAQyzpMo+uRwrln +INcDGwNx6p6rkjFbK27TME9ReCk+xQuVGaKOtqErKECXWDtD+0M35noyaOwWIFu2 +7gPZ0uGJ1n9ZMe/S9yZmmusaIrc66rX4o+fslUlH0g3SrH7yf83M8aOC2pEyCsG0 +mNNfwSFWfmu+1GMRHXJQ/qT8qBX8ZPhzRY2BAS6vr+eh3gwXR6yXLA8Xm1+e+iDU +gGTQoYkixDIL2nhvd4AFFlE977BiE+0sMS1eJKUUbQ36MLAWb5oOZKHrphEvqMKA +eGDO3qoDqB5TkZC3x38DXBDvAZ01d9s0fvveag== +-----END CERTIFICATE----- diff --git a/school/node_modules/node-forge/tests/server.key b/school/node_modules/node-forge/tests/server.key new file mode 100644 index 0000000..4024097 --- /dev/null +++ b/school/node_modules/node-forge/tests/server.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEApvxaG46ivAlT/1256coX9baaMmohX0oVDppVqi+ay3tENHQ0 +f2bq/rCzFL/9U+MDnxZI48b2dEpOTSIyt1stlAONWvjNyUU2wha4OLo7KLxWg+Ag +5le0XpNKiQd5uRqe4YLub3y/7/lq8MZ0DmzaviK0zEgNeXDuC8zSD4/StSzdnQfr +nE+8U0BRwH7yy4C5Qi4m3q6GmxeKxIYEzE25jLRVSkrfj8YECGD54cNVrgLxPYRX +rEUBXXwES6iGZPdhXh5ILR7/QQLp5LSXpnInW6MEwkwWjP543IItU3ovyxZKYfxQ +lchhEdKXpCTR1+tumwEEi6P7K7Fn5nJZfayumwIDAQABAoIBAFGPbEuNbXq+a6KN +GuNP7Ef9em8pW0d5nbNWOoU3XzoH6RZds86ObDUeBTobVBaHCRvI/K0UXwgJyxjt +nSvlguuKmJ5Ya9rkzYwbILvEamTJKNCcxjT7nYOcGYm4dwGsOPIYy3D006LYhh04 +MTNig6zessQcZUhtmjd1QRyMuPP4PaWVO79ic01jxZR/ip6tN/FjCYclPRi/FRi8 +bQVuGEVLW2qHgQbDKPpcXFyFjIqt7c9dL97/3eeIDp+SgdQ6bPi80J7v9p2MRyBP +7OPhX8ZDsAiZr4G4N0EbEzmWWpVSjAI3Nlmk8SLT4lu42KKyoZLtuKPjEOVI3/TR +0ktsc/ECgYEA27AHLnsv07Yqe7Z2bmv+GP8PKlwrPSHwqU/3Z5/1V590N+jo15N4 +lb7gvBUwwvXIxQQQVYJqRimqNQYVfT6+xRtQdtdqInxv2hvhc/cKPEiIHNpRh7OI +w7I59yNMlCnqLeRBiCOmd7ruCWoMGw+VLhsyArwUTXuqUK2oYN9qWm8CgYEAwpZF +XNm8xCFa+YeqP+WQzwK/0yUxHmYZs7ofh9ZIgHtqwHNKO/OA8+nGsZBaIl5xiyT4 +uZ/qZi2EkYzOmx0iSathiWQpSyc9kB+nOTdMHyhBOj8CgbTRRXIMjDQ6bz78Z09F +Nxenhwk2gSVr3oB2FG/BWc1rlmVlmGJIIX3QtJUCgYBfLhLOdpywExqw4srI6Iz8 +c3U0mx44rD3CfVzpTopTXkhR+Nz4mXIDHuHrWxr3PNmxUiNpiMlWgLK3ql0hGFA6 +wazI8GeRbWxgiPfS8FNE7v/Z0FTGgGhesRcgFfEVuFs3as9hlmCHOzvqZEG+b6/o +e+vc93OsZknSDosG/YTsjQKBgHrb7HGinLftI4a3rLvpU1QRNVK4gdnit0muM6hN +mLtesVlPschGh935ddW5Ad//Z4tmTZDOMm5PQQuxLuXrMDH5fn0D+7qSzSEJi0jp +7Csj/IMtM4T3yMYjK17+vwJsb2s/NsGBMupk28ARA5mZ3HQs15S+ybZM0Se0rjxP +Nw49AoGBAKrLTOtZta0DSGt7tURwQK1mERuGM8ZZdXjvIVTJIIknohD2u3/T+O4+ +ekFTUd6GQKOFd/hZ52t4wcRs7c7KE1Xen7vRHc8c6c3TkF9ldpLmK2AWT8WifQO6 +9Fjx2Wf8HM+CbrokQYH/OHSV9Xft8BRTOPHGUJlp1UsYikSwp4fW +-----END RSA PRIVATE KEY----- diff --git a/school/node_modules/node-forge/tests/server.py b/school/node_modules/node-forge/tests/server.py new file mode 100755 index 0000000..b5a5f06 --- /dev/null +++ b/school/node_modules/node-forge/tests/server.py @@ -0,0 +1,184 @@ +#!/usr/bin/env python + +""" +SSL server for Forge tests. + +- The server changes to the directory of the server script. +- SSL uses "server.key" and "server.crt". +- Sever performs basic static file serving. +- Starts Flash cross domain policy file server. +- Defaults to HTTP/HTTPS port 19400. +- Defaults to Flash socket policy port 19945. + + $ ./server.py [options] + +If you just need a simple HTTP server, also consider: + $ python -m SimpleHTTPServer 19400 +""" + +from multiprocessing import Process +from optparse import OptionParser +import SimpleHTTPServer +import SocketServer +import os +import sys +import time + +# Try to import special Forge SSL module with session cache support +# Using the built directory directly +python_version = "python" + sys.version[:3] +sys.path.insert(0, os.path.join( + os.path.dirname(os.path.realpath(__file__)), + "..", "dist", "forge_ssl", "lib", python_version, "site-packages")) +try: + from forge import ssl + have_ssl_sessions = True + have_ssl = True +except ImportError: + have_ssl_sessions = False + try: + import ssl + have_ssl = True + except ImportError: + have_ssl = False + +# Set address reuse for all TCPServers +SocketServer.TCPServer.allow_reuse_address = True + +# The policy file +# NOTE: This format is very strict. Edit with care. +policy_file = """\ +<?xml version="1.0"?>\ +<!DOCTYPE cross-domain-policy\ + SYSTEM "http://www.adobe.com/xml/dtds/cross-domain-policy.dtd">\ +<cross-domain-policy>\ +<allow-access-from domain="*" to-ports="*"/>\ +</cross-domain-policy>\0""" + + +class PolicyHandler(SocketServer.BaseRequestHandler): + """ + The RequestHandler class for our server. + + Returns a policy file when requested. + """ + + def handle(self): + # get some data + # TODO: make this more robust (while loop, etc) + self.data = self.request.recv(1024).rstrip('\0') + #print "%s wrote:" % self.client_address[0] + #print repr(self.data) + # if policy file request, send the file. + if self.data == "<policy-file-request/>": + print "Policy server request from %s." % (self.client_address[0]) + self.request.send(policy_file) + else: + print "Policy server received junk from %s: \"%s\"" % \ + (self.client_address[0], repr(self.data)) + + +def create_policy_server(options): + """Start a policy server""" + print "Policy serving from %d." % (options.policy_port) + policyd = SocketServer.TCPServer((options.host, options.policy_port), PolicyHandler) + return policyd + + +class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer): + pass + + +def create_http_server(options, script_dir): + """Start a static file server""" + # use UTF-8 encoding for javascript files + m = SimpleHTTPServer.SimpleHTTPRequestHandler.extensions_map + m['.js'] = 'application/javascript;charset=UTF-8' + + Handler = SimpleHTTPServer.SimpleHTTPRequestHandler +# httpd = SocketServer.TCPServer((options.host, options.port), Handler) + httpd = ThreadedTCPServer((options.host, options.port), Handler) + if options.tls: + if not have_ssl: + raise Exception("SSL support from Python 2.7 or later is required.") + + # setup session args if we session support + sess_args = {} + if have_ssl_sessions: + sess_args["sess_id_ctx"] = "forgetest" + else: + print "Forge SSL with session cache not available, using standard version." + + httpd.socket = ssl.wrap_socket( + httpd.socket, + keyfile="server.key", + certfile="server.crt", + server_side=True, + **sess_args) + + print "Serving from \"%s\"." % (script_dir) + print "%s://%s:%d/" % \ + (("https" if options.tls else "http"), + httpd.server_address[0], + options.port) + return httpd + + +def serve_forever(server): + """Serve until shutdown or keyboard interrupt.""" + try: + server.serve_forever() + except KeyboardInterrupt: + return + + +def main(): + """Start static file and policy servers""" + usage = "Usage: %prog [options]" + parser = OptionParser(usage=usage) + parser.add_option("", "--host", dest="host", metavar="HOST", + default="localhost", help="bind to HOST") + parser.add_option("-p", "--port", dest="port", type="int", + help="serve on PORT", metavar="PORT", default=19400) + parser.add_option("-P", "--policy-port", dest="policy_port", type="int", + help="serve policy file on PORT", metavar="PORT", default=19945) + parser.add_option("", "--tls", dest="tls", action="store_true", + help="serve HTTPS", default=False) + (options, args) = parser.parse_args() + + # Change to script dir so SSL and test files are in current dir. + script_dir = os.path.dirname(os.path.realpath(__file__)) + os.chdir(script_dir) + + print "Forge Test Server. Use ctrl-c to exit." + + # create policy and http servers + httpd = create_http_server(options, script_dir) + policyd = create_policy_server(options) + + # start servers + server_p = Process(target=serve_forever, args=(httpd,)) + policy_p = Process(target=serve_forever, args=(policyd,)) + server_p.start() + policy_p.start() + + processes = [server_p, policy_p] + + while len(processes) > 0: + try: + for p in processes: + if p.is_alive(): + p.join(1) + else: + processes.remove(p) + except KeyboardInterrupt: + print "\nStopping test server..." + # processes each receive interrupt + # so no need to shutdown + #httpd.shutdown(); + #policyd.shutdown(); + + +if __name__ == "__main__": + main() + diff --git a/school/node_modules/node-forge/tests/socketPool.html b/school/node_modules/node-forge/tests/socketPool.html new file mode 100644 index 0000000..33a095f --- /dev/null +++ b/school/node_modules/node-forge/tests/socketPool.html @@ -0,0 +1,299 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <link type="text/css" rel="stylesheet" media="all" href="screen.css" /> + <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script> + <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js"></script> + <script type="text/javascript" src="forge/util.js"></script> + <script type="text/javascript" src="forge/socket.js"></script> + <script type="text/javascript" src="forge/log.js"></script> + + <script type="text/javascript"> + //<![CDATA[ + // logging category + var cat = 'forge.tests.socketPool'; + + // feedback types + var ERROR = ''; + var USER = 'user'; + var SOCKETPOOL = 'socketpool' + var SOCKET = 'socket' + + function addFeedback(type, text) + { + var row = $('<tr/>') + .append($('<td/>').html(' ')) + .append($('<td/>').html(' ')) + .append($('<td/>').html(' ')); + switch(type) + { + case USER: + row.children().eq(0).html(text); + break; + case SOCKETPOOL: + row.children().eq(1).html(text); + break; + case SOCKET: + row.children().eq(2).html(text); + break; + default: + var msg = 'ERROR: bad feedback type:' + type; + row.children().eq(1).html(msg); + forge.log.error(cat, msg); + } + $('#feedback').append(row); + forge.log.debug(cat, '[' + type + ']', text); + }; + + function _setState(stateSel) + { + $('.sp-control').filter(stateSel).removeAttr('disabled'); + $('.sp-control').filter(':not(' + stateSel + ')').attr('disabled', 'disabled'); + $('.sp-state').filter(stateSel).addClass('sp-state-on'); + $('.sp-state').filter(':not(' + stateSel + ')').removeClass('sp-state-on'); + }; + + function setState(state) + { + switch(state) + { + case 'ready': + _setState('.sp-ready'); + break; + case 'initialized': + _setState('.sp-ready,.sp-initialized'); + break; + case 'created': + _setState('.sp-ready,.sp-initialized,.sp-created'); + break; + case 'connected': + _setState('.sp-ready,.sp-initialized,.sp-created,.sp-connected'); + break; + default: + addFeedback(ERROR, 'ERROR: bad state: ' + state); + }; + }; + + window.forge.socketPool = + { + ready: function() + { + $(document).ready(function() { + addFeedback(SOCKETPOOL, 'Ready'); + setState('ready'); + }); + } + }; + + swfobject.embedSWF( + "forge/SocketPool.swf", "socketPool", "0", "0", "9.0.0", + false, {}, {allowscriptaccess: 'always'}, {}); + + // local alias + var net = window.forge.net; + + // socket to use + var socket; + + $(document).ready(function() { + addFeedback(USER, 'Ready'); + $('#host').val(window.location.hostname); + $('#port').val(window.location.port); + }); + + function sp_init() + { + net.createSocketPool({ + flashId: 'socketPool', + policyPort: parseInt($('#policyPort').val()), + msie: false + }); + addFeedback(SOCKETPOOL, 'Initialized'); + setState('initialized'); + return false; + }; + + function sp_cleanup() + { + net.destroySocketPool({flashId: 'socketPool'}); + addFeedback(SOCKETPOOL, 'Cleaned up'); + setState('ready'); + return false; + }; + + function sp_create() + { + socket = net.createSocket({ + flashId: 'socketPool', + connected: function(e) + { + forge.log.debug(cat, 'connected', e); + addFeedback(SOCKET, 'Connected'); + }, + closed: function(e) + { + forge.log.debug(cat, 'closed', e); + addFeedback(SOCKET, 'Closed. Type: ' + e.type); + setState('created'); + }, + data: function(e) + { + forge.log.debug(cat, 'data received', e); + forge.log.debug(cat, 'bytes available', socket.bytesAvailable()); + addFeedback(SOCKET, + 'Data available: ' + + socket.bytesAvailable() +' bytes'); + var bytes = socket.receive(e.bytesAvailable); + forge.log.debug(cat, 'bytes received', bytes); + }, + error: function(e) + { + forge.log.error(cat, 'error', e); + addFeedback(SOCKET, 'Error: ' + e); + } + }); + addFeedback(SOCKETPOOL, 'Created socket'); + setState('created'); + return false; + }; + + function sp_destroy() + { + socket.destroy(); + addFeedback(USER, 'Request socket destroy'); + setState('initialized'); + return false; + }; + + function sp_connect() + { + socket.connect({ + host: $('#host').val(), + port: parseInt($('#port').val()), + policyPort: parseInt($('#policyPort').val()) + }); + addFeedback(USER, 'Request socket connect'); + setState('connected'); + }; + + function sp_isConnected() + { + var connected = socket.isConnected(); + addFeedback(USER, 'Socket connected check: ' + connected); + }; + + function sp_send() + { + socket.send('GET ' + $('#path').val() + ' HTTP/1.0\r\n\r\n'); + addFeedback(USER, 'Send GET request'); + }; + + function sp_close() + { + socket.close(); + addFeedback(USER, 'Requst socket close'); + setState('created'); + }; + //]]> + </script> + </head> + <body> + <div class="nav"><a href="index.html">Forge Tests</a> / SocketPool</div> + + <div class="header"> + <h1>SocketPool Test</h1> + </div> + + <div class="content"> + <!-- div used to hold the flash socket pool implemenation --> + <div id="socketPool"> + <p>Could not load the flash SocketPool.</p> + </div> + + <fieldset class="section"> + <ul> + <li>This page tests a single socket connection to the local test server.</li> + <li>Note that the selected server must serve a Flash cross-domain policy file on the selected policy port.</li> + <li>Additional output available in the JavaScript console.</li> + </ul> + </fieldset> + + <fieldset class="section"> + <legend>State</legend> + <p>State: + <span class="sp-state sp-ready">Ready</span> » + <span class="sp-state sp-initialized">Initialized</span> » + <span class="sp-state sp-created">Created</span> » + <span class="sp-state sp-connected">Connected</span> + </p> + </fieldset> + + <fieldset class="section"> + <legend>Controls</legend> + <div id="controls"> + <table> + <tr><th>Action</th><th>Description</th></tr> + <tr> + <td><button id="init" disabled="disabled" class="sp-control sp-ready" + onclick="javascript:return sp_init();">init</button></td> + <td>Initialize SocketPool system.</td> + </tr> + <tr> + <td><button id="cleanup" disabled="disabled" class="sp-control sp-initialized" + onclick="javascript:return sp_cleanup();">cleanup</button></td> + <td>Cleanup SocketPool system.</td> + </tr> + <tr> + <td><button id="create" disabled="disabled" class="sp-control sp-initialized" + onclick="javascript:return sp_create();">create socket</button></td> + <td>Create a new test socket.</td> + </tr> + <tr> + <td><button id="destroy" disabled="disabled" class="sp-control sp-created" + onclick="javascript:return sp_destroy();">destroy socket</button></td> + <td>Destroy the test socket.</td> + </tr> + <tr> + <td><button id="connect" disabled="disabled" class="sp-control sp-created" + onclick="javascript:return sp_connect();">connect</button></td> + <td>Connect the socket to + host: <input id="host"/> + port: <input id="port"/> + policy port: <input id="policyPort" value="19945"/> + </td> + </tr> + <tr> + <td><button id="isConnected" disabled="disabled" class="sp-control sp-created" + onclick="javascript:return sp_isConnected();">is connected</button></td> + <td>Check if socket is connected.</td> + </tr> + <tr> + <td><button id="send" disabled="disabled" class="sp-control sp-connected" + onclick="javascript:return sp_send();">send</button></td> + <td>Send a GET request for + path: <input id="path" value="/"/> + </td> + </tr> + <tr> + <td><button id="close" disabled="disabled" class="sp-control sp-connected" + onclick="javascript:return sp_close();">close</button></td> + <td>Close the test socket.</td> + </tr> + </table> + </div> + </fieldset> + + <fieldset class="section"> + <legend>Feedback</legend> + <table id="feedback"> + <tr> + <th>User</th> + <th>SocketPool</th> + <th>Socket</th> + </tr> + </table> + </fieldset> + </div> + </body> +</html> diff --git a/school/node_modules/node-forge/tests/tasks.html b/school/node_modules/node-forge/tests/tasks.html new file mode 100644 index 0000000..eba0173 --- /dev/null +++ b/school/node_modules/node-forge/tests/tasks.html @@ -0,0 +1,53 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head> + <title>Forge Tasks Test</title> + <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script> + <script type="text/javascript" src="forge/debug.js"></script> + <script type="text/javascript" src="forge/util.js"></script> + <script type="text/javascript" src="forge/log.js"></script> + <script type="text/javascript" src="forge/task.js"></script> + <script type="text/javascript" src="tasks.js"></script> + <link type="text/css" rel="stylesheet" media="all" href="screen.css" /> + <style type="text/css"> + .ready { color: inherit; background: inherit; } + .testing { color: black; background: yellow; } + .pass{ color: white; background: green; } + .fail{ color: white; background: red; } + </style> + </head> +<body> +<div class="nav"><a href="index.html">Forge Tests</a> / Tasks</div> + +<div class="header"> + <h1>Task Tests</h1> +</div> + +<div class="content"> + +<fieldset class="section"> +<legend>Control</legend> + <button id="start">Start</button> + <button id="reset">Reset</button> + <br/> + <input id="scroll" type="checkbox" checked="checked" />Scroll Tests +</fieldset> + +<fieldset class="section"> +<legend>Progress</legend> +Status: <span id="status">?</span><br/> +Pass: <span id="pass">?</span>/<span id="total">?</span><br/> +Fail: <span id="fail">?</span> +</fieldset> + +<fieldset class="section"> +<legend>Tests</legend> +<div id="tests"></div> +</fieldset> + +</div> + +</body> +</html> diff --git a/school/node_modules/node-forge/tests/tasks.js b/school/node_modules/node-forge/tests/tasks.js new file mode 100644 index 0000000..dd3ffde --- /dev/null +++ b/school/node_modules/node-forge/tests/tasks.js @@ -0,0 +1,378 @@ +/** + * Forge Tasks Test + * + * @author David I. Lehn <dlehn@digitalbazaar.com> + * + * Copyright (c) 2009-2010 Digital Bazaar, Inc. All rights reserved. + */ +jQuery(function($) +{ + var cat = 'forge.tests.tasks'; + + var tests = []; + var passed = 0; + var failed = 0; + + var init = function() { + passed = failed = 0; + $('.ready,.testing,.pass,.fail') + .removeClass('ready testing pass fail'); + $('#status') + .text('Ready.') + .addClass('ready'); + $('#total').text(tests.length); + $('#pass').text(passed); + $('#fail').text(failed); + $('.expect').empty(); + $('.result').empty(); + $('.time').empty(); + $('#start').removeAttr('disabled'); + }; + + var start = function() + { + $('#start').attr('disabled', 'disabled'); + // meta! use tasks to run the task tests + forge.task.start({ + type: 'test', + run: function(task) { + task.next('starting', function(task) { + forge.log.debug(cat, 'start'); + $('#status') + .text('Testing...') + .addClass('testing') + .removeClass('idle'); + }); + $.each(tests, function(i, test) { + task.next('test', function(task) { + var title = $('li:first', test.container); + if($('#scroll:checked').length === 1) + { + $('html,body').animate({scrollTop: title.offset().top}); + } + title.addClass('testing'); + test.run(task, test); + }); + task.next('test', function(task) { + $('li:first', test.container).removeClass('testing'); + }); + }); + task.next('success', function(task) { + forge.log.debug(cat, 'done'); + if(failed === 0) { + $('#status') + .text('PASS') + .addClass('pass') + .removeClass('testing'); + } else { + // FIXME: should just be hitting failure() below + $('#status') + .text('FAIL') + .addClass('fail') + .removeClass('testing'); + } + }); + }, + failure: function() { + $('#status') + .text('FAIL') + .addClass('fail') + .removeClass('testing'); + } + }); + }; + + $('#start').click(function() { + start(); + }); + + $('#reset').click(function() { + init(); + }); + + var addTest = function(name, run) + { + var container = $('<ul><li>Test ' + name + '</li><ul/></ul>'); + var expect = $('<li>Expect: <span class="expect"/></li>'); + var result = $('<li>Result: <span class="result"/></li>'); + var time = $('<li>Time: <span class="time"/></li>'); + $('ul', container).append(expect).append(result).append(time); + $('#tests').append(container); + var test = { + container: container, + startTime: null, + run: function(task, test) { + test.startTime = new Date(); + run(task, test); + }, + expect: $('span', expect), + result: $('span', result), + check: function() { + var e = test.expect.text(); + var r = test.result.text(); + (e == r) ? test.pass() : test.fail(); + }, + pass: function() { + passed += 1; + $('#pass').text(passed); + $('li:first', container).addClass('pass'); + var dt = new Date() - test.startTime; + $('span.time', container).html(dt); + }, + fail: function() { + failed += 1; + $('#fail').text(failed); + $('li:first', container).addClass('fail'); + var dt = new Date() - test.startTime; + $('span.time', container).html(dt); + } + }; + tests.push(test); + }; + + addTest('pass', function(task, test) { + test.pass(); + }); + + addTest('check', function(task, test) { + test.check(); + }); + + addTest('task 1', function(task, test) { + task.next(function(task) { + test.pass(); + }); + }); + + addTest('task check()', function(task, test) { + test.expect.append('check'); + task.next(function(task) { + test.result.append('check'); + }); + task.next(function(task) { + test.check(); + }); + }); + + addTest('serial 20', function(task, test) { + // total + var n = 20; + // counter used in the tasks + var taskn = 0; + for(var i = 0; i < n; ++i) { + test.expect.append(i + ' '); + task.next(function(task) { + test.result.append(taskn++ + ' '); + }); + } + task.next(function(task) { + test.check(); + }); + }); + + addTest('ajax block', function(task, test) { + test.expect.append('.'); + task.next(function(task) { + task.parent.block(); + $.ajax({ + type: 'GET', + url: 'tasks.html', + success: function() { + test.result.append('.'); + task.parent.unblock(); + } + }); + }); + task.next(function(task) { + test.check(); + }); + }); + + addTest('serial ajax', function(task, test) { + var n = 10; + for(var i = 0; i < n; ++i) + { + test.expect.append(i + ' '); + } + task.next(function(task) { + // create parallel functions + task.parent.block(n); + for(var i = 0; i < n; ++i) + { + // pass value into closure + (function(i) + { + // serial tasks + task.next(function(ajaxTask) + { + $.ajax({ + type: 'GET', + url: 'tasks.html', + success: function() { + // results use top level task + test.result.append(i + ' '); + task.parent.unblock(); + } + }); + }); + })(i); + } + }); + task.next(function(task) { + test.check(); + }); + }); + + addTest('parallel ajax', function(task, test) { + task.next(function(task) { + var n = 10; + // create parallel functions + var tasks = []; + for(var i = 0; i < n; ++i) + { + // pass value into closure + (function(i) + { + tasks.push(function(ajaxTask) + { + $.ajax({ + type: 'GET', + url: 'tasks.html', + success: function() { + // results use top level task + test.result.append(i + ' '); + } + }); + }); + })(i); + } + // launch in parallel + task.parallel(tasks); + }); + task.next(function(task) { + test.pass(); + }); + }); + + addTest('linear empty tasks rate', function(task, test) { + test.expect.append('-'); + // total + var n = 100; + var start = new Date(); + for(var i = 0; i < n; ++i) { + // empty task + task.next(function(task) {}); + } + task.next(function(task) { + var dt = (new Date() - start) / 1000; + var res = $('<ul/>') + .append('<li>Tasks: ' + n + '</li>') + .append('<li>Time: ' + dt + 's</li>') + .append('<li>Rate: ' + n/dt + ' tasks/s</li>') + .append('<li>Task Time: ' + 1000*dt/n + ' ms/tasks</li>'); + test.result.html(res); + test.pass(); + }); + }); + + addTest('sleep', function(task, test) { + test.expect.append('-'); + var st = 1000; + var start = new Date(); + task.next(function(task) { + task.sleep(st); + }); + task.next(function(task) { + var dt = new Date() - start; + var res = $('<ul/>') + .append('<li>Sleep Time : ' + st + 'ms</li>') + .append('<li>Real Time: ' + dt + 'ms</li>') + .append('<li>Diff: ' + (dt-st) + 'ms</li>'); + test.result.html(res); + test.pass(); + }); + }); + + addTest('serial 20 + sleep', function(task, test) { + // total + var n = 20; + // counter used in the tasks + var taskn = 0; + for(var i = 0; i < n; ++i) { + test.expect.append(i + ' '); + task.next(function(task) { + task.sleep(20); + test.result.append(taskn++ + ' '); + }); + } + task.next(function(task) { + test.check(); + }); + }); + + addTest('concurrent tasks', function(task, test) + { + var colors = [ + 'red', + 'green', + 'blue', + 'black', + 'purple', + 'goldenrod', + 'maroon', + 'gray', + 'teal', + 'magenta' + ]; + var count = colors.length; + task.next(function(task) + { + var main = task; + task.block(count); + + var tasks = []; + for(var i = 0; i < count; ++i) + { + var makefunction = function(index) + { + return function(task) + { + // total + var n = 20; + // counter used in the tasks + var taskn = 0; + for(var j = 0; j < n; j++) + { + task.next(function(task) + { + test.result.append( + '<span style=\"color:' + colors[index] + ';\">' + + taskn++ + '</span> '); + }); + } + task.next(function(task) + { + main.unblock(); + }); + }; + }; + tasks.push( + { + type: 'concurrent' + i, + run: makefunction(i) + }); + } + + for(var i = 0; i < count; ++i) + { + forge.task.start(tasks[i]); + } + }); + + task.next(function(task) { + test.pass(); + }); + }); + + init(); +}); diff --git a/school/node_modules/node-forge/tests/tls.html b/school/node_modules/node-forge/tests/tls.html new file mode 100644 index 0000000..92501b8 --- /dev/null +++ b/school/node_modules/node-forge/tests/tls.html @@ -0,0 +1,426 @@ +<html> + <head> + <link type="text/css" rel="stylesheet" media="all" href="screen.css" /> + <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js"></script> + <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script> + <script type="text/javascript" src="forge/debug.js"></script> + <script type="text/javascript" src="forge/util.js"></script> + <script type="text/javascript" src="forge/log.js"></script> + <script type="text/javascript" src="forge/socket.js"></script> + <script type="text/javascript" src="forge/md5.js"></script> + <script type="text/javascript" src="forge/sha1.js"></script> + <script type="text/javascript" src="forge/hmac.js"></script> + <script type="text/javascript" src="forge/aes.js"></script> + <script type="text/javascript" src="forge/pem.js"></script> + <script type="text/javascript" src="forge/asn1.js"></script> + <script type="text/javascript" src="forge/jsbn.js"></script> + <script type="text/javascript" src="forge/prng.js"></script> + <script type="text/javascript" src="forge/random.js"></script> + <script type="text/javascript" src="forge/oids.js"></script> + <script type="text/javascript" src="forge/rsa.js"></script> + <script type="text/javascript" src="forge/pbe.js"></script> + <script type="text/javascript" src="forge/x509.js"></script> + <script type="text/javascript" src="forge/pki.js"></script> + <script type="text/javascript" src="forge/tls.js"></script> + <script type="text/javascript" src="forge/aesCipherSuites.js"></script> + <script type="text/javascript" src="forge/tlssocket.js"></script> + <script type="text/javascript" src="forge/http.js"></script> + <script type="text/javascript" src="ws-webid.js"></script> + + <script type="text/javascript"> + //<![CDATA[ + // logging category + var cat = 'forge.tests.tls'; + + swfobject.embedSWF( + 'forge/SocketPool.swf', 'socketPool', '0', '0', '9.0.0', + false, {}, {allowscriptaccess: 'always'}, {}); + + // CA certificate for test server + var certificatePem = + '-----BEGIN CERTIFICATE-----\r\n' + + 'MIIEaDCCA1CgAwIBAgIJAJuj0AjEWncuMA0GCSqGSIb3DQEBBQUAMH8xCzAJBgNV\r\n' + + 'BAYTAlVTMREwDwYDVQQIEwhWaXJnaW5pYTETMBEGA1UEBxMKQmxhY2tzYnVyZzEd\r\n' + + 'MBsGA1UEChMURGlnaXRhbCBCYXphYXIsIEluYy4xGjAYBgNVBAsTEUZvcmdlIFRl\r\n' + + 'c3QgU2VydmVyMQ0wCwYDVQQDEwR0ZXN0MB4XDTEwMDcxMzE3MjAzN1oXDTMwMDcw\r\n' + + 'ODE3MjAzN1owfzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMRMwEQYD\r\n' + + 'VQQHEwpCbGFja3NidXJnMR0wGwYDVQQKExREaWdpdGFsIEJhemFhciwgSW5jLjEa\r\n' + + 'MBgGA1UECxMRRm9yZ2UgVGVzdCBTZXJ2ZXIxDTALBgNVBAMTBHRlc3QwggEiMA0G\r\n' + + 'CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCm/FobjqK8CVP/Xbnpyhf1tpoyaiFf\r\n' + + 'ShUOmlWqL5rLe0Q0dDR/Zur+sLMUv/1T4wOfFkjjxvZ0Sk5NIjK3Wy2UA41a+M3J\r\n' + + 'RTbCFrg4ujsovFaD4CDmV7Rek0qJB3m5Gp7hgu5vfL/v+WrwxnQObNq+IrTMSA15\r\n' + + 'cO4LzNIPj9K1LN2dB+ucT7xTQFHAfvLLgLlCLiberoabF4rEhgTMTbmMtFVKSt+P\r\n' + + 'xgQIYPnhw1WuAvE9hFesRQFdfARLqIZk92FeHkgtHv9BAunktJemcidbowTCTBaM\r\n' + + '/njcgi1Tei/LFkph/FCVyGER0pekJNHX626bAQSLo/srsWfmcll9rK6bAgMBAAGj\r\n' + + 'geYwgeMwHQYDVR0OBBYEFCau5k6jxezjULlLuo/liswJlBF8MIGzBgNVHSMEgasw\r\n' + + 'gaiAFCau5k6jxezjULlLuo/liswJlBF8oYGEpIGBMH8xCzAJBgNVBAYTAlVTMREw\r\n' + + 'DwYDVQQIEwhWaXJnaW5pYTETMBEGA1UEBxMKQmxhY2tzYnVyZzEdMBsGA1UEChMU\r\n' + + 'RGlnaXRhbCBCYXphYXIsIEluYy4xGjAYBgNVBAsTEUZvcmdlIFRlc3QgU2VydmVy\r\n' + + 'MQ0wCwYDVQQDEwR0ZXN0ggkAm6PQCMRady4wDAYDVR0TBAUwAwEB/zANBgkqhkiG\r\n' + + '9w0BAQUFAAOCAQEAnP/2mzFWaoGx6+KAfY8pcgnF48IoyKPx5cAQyzpMo+uRwrln\r\n' + + 'INcDGwNx6p6rkjFbK27TME9ReCk+xQuVGaKOtqErKECXWDtD+0M35noyaOwWIFu2\r\n' + + '7gPZ0uGJ1n9ZMe/S9yZmmusaIrc66rX4o+fslUlH0g3SrH7yf83M8aOC2pEyCsG0\r\n' + + 'mNNfwSFWfmu+1GMRHXJQ/qT8qBX8ZPhzRY2BAS6vr+eh3gwXR6yXLA8Xm1+e+iDU\r\n' + + 'gGTQoYkixDIL2nhvd4AFFlE977BiE+0sMS1eJKUUbQ36MLAWb5oOZKHrphEvqMKA\r\n' + + 'eGDO3qoDqB5TkZC3x38DXBDvAZ01d9s0fvveag==\r\n' + + '-----END CERTIFICATE-----'; + + // local aliases + var net = window.forge.net; + var tls = window.forge.tls; + var http = window.forge.http; + var util = window.forge.util; + + var client; + + function client_init(primed) + { + try + { + var sp = net.createSocketPool({ + flashId: 'socketPool', + policyPort: 19945, + msie: false + }); + client = http.createClient({ + //url: 'https://localhost:4433', + url: 'https://' + window.location.host, + socketPool: sp, + connections: 10, + caCerts: [certificatePem], + // optional cipher suites in order of preference + cipherSuites: [ + tls.CipherSuites.TLS_RSA_WITH_AES_128_CBC_SHA, + tls.CipherSuites.TLS_RSA_WITH_AES_256_CBC_SHA], + verify: function(c, verified, depth, certs) + { + forge.log.debug(cat, + 'TLS certificate ' + depth + ' verified', verified); + // Note: change to always true to test verifying without cert + //return verified; + // FIXME: temporarily accept any cert to allow hitting any bpe + if(verified !== true) + { + forge.log.warning(cat, + 'Certificate NOT verified. Ignored for test.'); + } + return true; + }, + primeTlsSockets: primed + }); + document.getElementById('feedback').innerHTML = + 'http client created'; + } + catch(ex) + { + forge.log.error(cat, ex); + } + + return false; + } + + function client_cleanup() + { + var sp = client.socketPool; + client.destroy(); + sp.destroy(); + document.getElementById('feedback').innerHTML = + 'http client cleaned up'; + return false; + } + + function client_send() + { + /* + var request = http.createRequest({ + method: 'POST', + path: '/', + body: 'echo=foo', + headers: [{'Content-Type': 'application/x-www-form-urlencoded'}] + }); + */ + var request = http.createRequest({ + method: 'GET', + path: '/' + }); + + client.send({ + request: request, + connected: function(e) + { + forge.log.debug(cat, 'connected', e); + }, + headerReady: function(e) + { + forge.log.debug(cat, 'header ready', e); + }, + bodyReady: function(e) + { + forge.log.debug(cat, 'body ready', e); + + // FIXME: current test server doesn't seem to handle keep-alive + // correctly, so close connection + e.socket.close(); + }, + error: function(e) + { + forge.log.error(cat, 'error', e); + } + }); + document.getElementById('feedback').innerHTML = + 'http request sent'; + return false; + } + + function client_send_10() + { + for(var i = 0; i < 10; ++i) + { + client_send(); + } + return false; + } + + function client_stress() + { + for(var i = 0; i < 10; ++i) + { + setTimeout(function() + { + for(var i = 0; i < 10; ++i) + { + client_send(); + } + }, 0); + } + return false; + } + + function client_cookies() + { + var cookie = + { + name: 'test-cookie', + value: 'test-value', + maxAge: -1, + secure: true, + path: '/' + }; + client.setCookie(cookie); + forge.log.debug(cat, 'cookie', client.getCookie('test-cookie')); + } + + function client_clear_cookies() + { + client.clearCookies(); + } + + function websocket_test() + { + // create certificate + var cn = 'client'; + console.log( + 'Generating 512-bit key-pair and certificate for \"' + cn + '\".'); + var keys = forge.pki.rsa.generateKeyPair(512); + console.log('key-pair created.'); + + var cert = forge.pki.createCertificate(); + cert.serialNumber = '01'; + cert.validity.notBefore = new Date(); + cert.validity.notAfter = new Date(); + cert.validity.notAfter.setFullYear( + cert.validity.notBefore.getFullYear() + 1); + var attrs = [{ + name: 'commonName', + value: cn + }, { + name: 'countryName', + value: 'US' + }, { + shortName: 'ST', + value: 'Virginia' + }, { + name: 'localityName', + value: 'Blacksburg' + }, { + name: 'organizationName', + value: 'Test' + }, { + shortName: 'OU', + value: 'Test' + }]; + cert.setSubject(attrs); + cert.setIssuer(attrs); + cert.setExtensions([{ + name: 'basicConstraints', + cA: true + }, { + name: 'keyUsage', + keyCertSign: true, + digitalSignature: true, + nonRepudiation: true, + keyEncipherment: true, + dataEncipherment: true + }, { + name: 'subjectAltName', + altNames: [{ + type: 6, // URI + value: 'http://myuri.com/webid#me' + }] + }]); + // FIXME: add subjectKeyIdentifier extension + // FIXME: add authorityKeyIdentifier extension + cert.publicKey = keys.publicKey; + + // self-sign certificate + cert.sign(keys.privateKey); + + // save cert and private key in PEM format + cert = forge.pki.certificateToPem(cert); + privateKey = forge.pki.privateKeyToPem(keys.privateKey); + console.log('certificate created for \"' + cn + '\": \n' + cert); + + // create websocket + var ws = new WebSocket('ws://localhost:8080'); + console.log('created websocket', ws); + + // create TLS client + var success = false; + var tls = forge.tls.createConnection( + { + server: false, + caStore: [], + sessionCache: {}, + // supported cipher suites in order of preference + cipherSuites: [ + forge.tls.CipherSuites.TLS_RSA_WITH_AES_128_CBC_SHA, + forge.tls.CipherSuites.TLS_RSA_WITH_AES_256_CBC_SHA], + virtualHost: 'server', + verify: function(c, verified, depth, certs) + { + console.log( + 'TLS Client verifying certificate w/CN: \"' + + certs[0].subject.getField('CN').value + + '\", verified: ' + verified + '...'); + // accept any certificate from the server for this test + return true; + }, + connected: function(c) + { + console.log('Client connected...'); + + // send message to server + setTimeout(function() + { + c.prepare('Hello Server'); + }, 1); + }, + getCertificate: function(c, hint) + { + console.log('Client getting certificate ...'); + return cert; + }, + getPrivateKey: function(c, cert) + { + return privateKey; + }, + tlsDataReady: function(c) + { + // send base64-encoded TLS data to server + ws.send(forge.util.encode64(c.tlsData.getBytes())); + }, + dataReady: function(c) + { + var response = c.data.getBytes(); + console.log('Client received \"' + response + '\"'); + success = (response === 'Hello Client'); + c.close(); + }, + closed: function(c) + { + console.log('Client disconnected.'); + if(success) + { + console.log('PASS'); + } + else + { + console.log('FAIL'); + } + }, + error: function(c, error) + { + console.log('Client error: ' + error.message); + } + }); + + ws.onopen = function(evt) + { + console.log('websocket connected'); + + // do TLS handshake + tls.handshake(); + }; + ws.onmessage = function(evt) + { + // base64-decode data and process it + tls.process(forge.util.decode64(evt.data)); + }; + ws.onclose = function(evt) + { + console.log('websocket closed'); + }; + } + + //]]> + </script> + </head> + <body> + <div class="nav"><a href="index.html">Forge Tests</a> / TLS</div> + + <div class="header"> + <h1>TLS Test</h1> + </div> + + <div class="content"> + + <!-- div used to hold the flash socket pool implemenation --> + <div id="socketPool"> + <p>Could not load the flash SocketPool.</p> + </div> + + <fieldset class="section"> + <ul> + <li>Use the controls below to test the HTTP client over TLS.</li> + <li>You currently need a JavaScript console to view the output.</li> + <li>This test connects to a TLS server so you must have one running. The easiest way to run this test is to start the test server with --tls and load this page over HTTPS.</li> + </ul> + </fieldset> + + <fieldset class="section"> + <legend>Controls</legend> + <div id="controls"> + <button id="init" onclick="javascript:return client_init(false);">init</button> + <button id="init_primed" onclick="javascript:return client_init(true);">init primed</button> + <button id="cleanup" onclick="javascript:return client_cleanup();">cleanup</button> + <button id="send" onclick="javascript:return client_send();">send</button> + <button id="send10" onclick="javascript:return client_send_10();">send 10</button> + <button id="stress" onclick="javascript:return client_stress();">stress</button> + <button id="client_cookies" onclick="javascript:return client_cookies();">cookies</button> + <button id="clear_cookies" onclick="javascript:return client_clear_cookies();">clear cookies</button> + <button id="websocket" onclick="javascript:return websocket_test();">websocket test</button> + <button id="websocket-webid" onclick="javascript:return websocket_webid('localhost', 8080);">websocket webid test</button> + </div> + </fieldset> + + <fieldset class="section"> + <legend>Feedback</legend> + <p>Feedback from the flash SocketPool:</p> + <div id="feedback"> + None + </div> + </fieldset> + + </div> + </body> +</html> diff --git a/school/node_modules/node-forge/tests/webid.html b/school/node_modules/node-forge/tests/webid.html new file mode 100644 index 0000000..8c8d795 --- /dev/null +++ b/school/node_modules/node-forge/tests/webid.html @@ -0,0 +1,110 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head> + <title>Web ID Test</title> + <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js"></script> + <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script> + <script type="text/javascript" src="forge/debug.js"></script> + <script type="text/javascript" src="forge/util.js"></script> + <script type="text/javascript" src="forge/log.js"></script> + <script type="text/javascript" src="forge/task.js"></script> + <script type="text/javascript" src="forge/socket.js"></script> + <script type="text/javascript" src="forge/md5.js"></script> + <script type="text/javascript" src="forge/sha1.js"></script> + <script type="text/javascript" src="forge/hmac.js"></script> + <script type="text/javascript" src="forge/aes.js"></script> + <script type="text/javascript" src="forge/pem.js"></script> + <script type="text/javascript" src="forge/asn1.js"></script> + <script type="text/javascript" src="forge/jsbn.js"></script> + <script type="text/javascript" src="forge/prng.js"></script> + <script type="text/javascript" src="forge/random.js"></script> + <script type="text/javascript" src="forge/oids.js"></script> + <script type="text/javascript" src="forge/rsa.js"></script> + <script type="text/javascript" src="forge/pbe.js"></script> + <script type="text/javascript" src="forge/x509.js"></script> + <script type="text/javascript" src="forge/pki.js"></script> + <script type="text/javascript" src="forge/tls.js"></script> + <script type="text/javascript" src="forge/aesCipherSuites.js"></script> + <script type="text/javascript" src="forge/tlssocket.js"></script> + <script type="text/javascript" src="forge/http.js"></script> + <script type="text/javascript" src="forge/xhr.js"></script> + <script type="text/javascript" src="webid.js"></script> + + <link type="text/css" rel="stylesheet" media="all" href="screen.css" /> + <style type="text/css"> + .ready { color: inherit; background: inherit; } + .testing { color: black; background: yellow; } + .pass{ color: white; background: green; } + .fail{ color: white; background: red; } + </style> + </head> +<body> +<div class="nav"><a href="index.html">Forge Tests</a> / Web ID</div> + +<div class="header"> + <h1>Web ID Tests</h1> +</div> + +<div class="content"> + +<!-- div used to hold the flash socket pool implementation --> +<div id="socketPool"> + <p>Could not load the flash SocketPool.</p> +</div> + +<fieldset class="section"> + <ul> + <li>Use the controls below to test Web ID.</li> + <li>Use 512 bits or less on slower JavaScript implementations.</li> + </ul> +</fieldset> + +<fieldset class="section"> +<legend>Control</legend> + <table> + <tr> + <td rowspan="3"><button id="create">Create Web ID</button></td> + <td>Bits</td> + <td><input id="bits" size=8 value="1024"/></td> + </tr> + <tr> + <td>URI</td> + <td><input id="uri" size=60 value="http://localhost/dataspace/person/myname#this"/></td> + </tr> + <tr> + <td>Common Name</td> + <td><input id="commonName" size=20 value="mycert"/></td> + </tr> + <tr> + <td><button id="show">Show Web IDs</button></td> + <td> </td> + <td> </td> + </tr> + <tr> + <td><button id="clear">Delete Web IDs</button></td> + <td> </td> + <td> </td> + </tr> + <tr> + <td><button id="authenticate">Authenticate using Web ID</button></td> + <td>URI</td> + <td><input id="webid" size=60 value="http://localhost/dataspace/person/myname#this"/></td> + </tr> + </table> +</fieldset> + +<fieldset class="section"> +<legend>Progress</legend> + <div id="progress"></div> +</fieldset> + +<fieldset class="section"> +<legend>Available Web IDs</legend> +<div id="webids"></div> +</fieldset> + +</div> +</body> +</html> diff --git a/school/node_modules/node-forge/tests/webid.js b/school/node_modules/node-forge/tests/webid.js new file mode 100644 index 0000000..7c07ab9 --- /dev/null +++ b/school/node_modules/node-forge/tests/webid.js @@ -0,0 +1,313 @@ +/** + * Forge Web ID Tests + * + * @author Dave Longley + * + * Copyright (c) 2010 Digital Bazaar, Inc. All rights reserved. + */ +(function($) +{ + // load flash socket pool + window.forge.socketPool = {}; + window.forge.socketPool.ready = function() + { + // init forge xhr + forge.xhr.init({ + flashId: 'socketPool', + policyPort: 19945, + msie: $.browser.msie, + connections: 10, + caCerts: [], + verify: function(c, verified, depth, certs) + { + // don't care about cert verification for test + return true; + } + }); + }; + swfobject.embedSWF( + 'forge/SocketPool.swf', 'socketPool', '0', '0', '9.0.0', + false, {}, {allowscriptaccess: 'always'}, {}); +})(jQuery); + +jQuery(function($) +{ + var cat = 'forge.tests.webid'; + + // local alias + var forge = window.forge; + + $('#create').click(function() + { + var bits = $('#bits')[0].value; + var uri = $('#uri')[0].value; + var commonName = $('#commonName')[0].value; + forge.log.debug(cat, 'generating ' + bits + + '-bit RSA key-pair and certificate...'); + + // function to create cert + var createCert = function(keys) + { + try + { + var cert = forge.pki.createCertificate(); + cert.serialNumber = '01'; + cert.validity.notBefore = new Date(); + cert.validity.notAfter = new Date(); + cert.validity.notAfter.setFullYear( + cert.validity.notBefore.getFullYear() + 1); + var attrs = [{ + name: 'commonName', + value: commonName + }, { + name: 'countryName', + value: 'US' + }, { + shortName: 'ST', + value: 'Virginia' + }, { + name: 'localityName', + value: 'Blacksburg' + }, { + name: 'organizationName', + value: 'Test' + }, { + shortName: 'OU', + value: 'Test' + }]; + cert.setSubject(attrs); + cert.setIssuer(attrs); + cert.setExtensions([{ + name: 'basicConstraints', + cA: true + }, { + name: 'keyUsage', + keyCertSign: true, + digitalSignature: true, + nonRepudiation: true, + keyEncipherment: true, + dataEncipherment: true + }, { + name: 'subjectAltName', + altNames: [{ + type: 6, // URI + value: uri + }] + }]); + // FIXME: add subjectKeyIdentifier extension + // FIXME: add authorityKeyIdentifier extension + cert.publicKey = keys.publicKey; + + // self-sign certificate + cert.sign(keys.privateKey); + + // verify certificate + forge.log.debug('verified', cert.verify(cert)); + + forge.log.debug(cat, 'certificate:', cert); + //forge.log.debug(cat, + // forge.asn1.prettyPrint(forge.pki.certificateToAsn1(cert))); + var keyPem = forge.pki.privateKeyToPem(keys.privateKey); + var certPem = forge.pki.certificateToPem(cert); + forge.log.debug(cat, keyPem); + forge.log.debug(cat, certPem); + + forge.log.debug(cat, 'storing certificate and private key...'); + try + { + // get flash API + var flashApi = document.getElementById('socketPool'); + + // get web ids collection + var webids = forge.util.getItem( + flashApi, 'forge.test.webid', 'webids'); + webids = webids || {}; + + // add web id + webids[uri] = { + certificate: certPem, + privateKey: keyPem + }; + + // update web ids collection + forge.util.setItem( + flashApi, 'forge.test.webid', 'webids', webids); + + forge.log.debug(cat, 'certificate and private key stored'); + $('#show').click(); + } + catch(ex) + { + forge.log.error(cat, ex); + } + } + catch(ex) + { + forge.log.error(cat, ex, ex.message ? ex.message : ''); + } + }; + + // create key-generation state and function to step algorithm + var progress = $('#progress'); + progress.html('Generating ' + bits + '-bit key-pair.'); + var state = forge.pki.rsa.createKeyPairGenerationState(bits); + var kgTime = +new Date(); + var step = function() + { + // step key-generation + if(!forge.pki.rsa.stepKeyPairGenerationState(state, 1000)) + { + progress.html(progress.html() + '.'); + setTimeout(step, 1); + } + // key-generation complete + else + { + kgTime = +new Date() - kgTime; + forge.log.debug(cat, 'Total key-gen time', kgTime + 'ms'); + createCert(state.keys); + progress.html(progress.html() + 'done. Time=' + kgTime + 'ms'); + } + }; + + // run key-gen algorithm + setTimeout(step, 0); + }); + + $('#show').click(function() + { + forge.log.debug(cat, 'get stored web IDs...'); + try + { + // get flash API + var flashApi = document.getElementById('socketPool'); + + // get web ids collection + var webids = forge.util.getItem( + flashApi, 'forge.test.webid', 'webids'); + webids = webids || {}; + + var html = '<ul>'; + var webid, cert; + for(var key in webids) + { + webid = webids[key]; + cert = forge.pki.certificateFromPem(webid.certificate); + html += '<li><p>' + key + '</p>'; + + var attr; + for(var n = 0; n < cert.subject.attributes.length; ++n) + { + attr = cert.subject.attributes[n]; + html += attr.name + ': ' + attr.value + '<br/>'; + } + + //html += '<p>' + webid.certificate + '</p></li>'; + html += '</li>'; + } + if(html === '<ul>') + { + html = 'None'; + } + else + { + html += '</ul>'; + } + + $('#webids').html(html); + + forge.log.debug(cat, 'Web IDs retrieved'); + } + catch(ex) + { + forge.log.error(cat, ex); + } + }); + + $('#clear').click(function() + { + forge.log.debug(cat, 'clearing all web IDs...'); + try + { + // get flash API + var flashApi = document.getElementById('socketPool'); + forge.util.clearItems(flashApi, 'forge.test.webid'); + $('#webids').html('None'); + forge.log.debug(cat, 'Web IDs cleared'); + } + catch(ex) + { + forge.log.error(cat, ex); + } + }); + + $('#authenticate').click(function() + { + forge.log.debug(cat, 'doing Web ID authentication...'); + + try + { + // get flash API + var flashApi = document.getElementById('socketPool'); + + // get web ids collection + var webids = forge.util.getItem( + flashApi, 'forge.test.webid', 'webids'); + webids = webids || {}; + + var uri = $('#webid')[0].value; + var webid = webids[uri]; + + $.ajax( + { + type: 'GET', + url: '/', + success: function(data, textStatus, xhr) + { + if(data !== '') + { + forge.log.debug(cat, 'authentication completed'); + forge.log.debug(cat, data); + } + else + { + forge.log.error(cat, 'authentication failed'); + } + }, + error: function(xhr, textStatus, errorThrown) + { + forge.log.error(cat, 'authentication failed'); + }, + xhr: function() + { + return forge.xhr.create({ + // FIXME: change URL + url: 'https://localhost:4433', + connections: 10, + caCerts: [], + verify: function(c, verified, depth, certs) + { + // don't care about cert verification for test + return true; + }, + getCertificate: function(c) + { + //forge.log.debug(cat, 'using cert', webid.certificate); + return webid.certificate; + }, + getPrivateKey: function(c) + { + //forge.log.debug(cat, + // 'using private key', webid.privateKey); + return webid.privateKey; + } + }); + } + }); + } + catch(ex) + { + forge.log.error(cat, ex); + } + }); +}); diff --git a/school/node_modules/node-forge/tests/ws-webid.js b/school/node_modules/node-forge/tests/ws-webid.js new file mode 100644 index 0000000..2ce5816 --- /dev/null +++ b/school/node_modules/node-forge/tests/ws-webid.js @@ -0,0 +1,132 @@ +var websocket_webid = function(host, port) +{ + var cat = 'ws'; + + // TODO: get private key and certificate from local storage + var privateKey = + '-----BEGIN RSA PRIVATE KEY-----\r\n' + +'MIICXAIBAAKBgQCTmE8QLARsC57Z1OrOaLM6AS3fn70N7BvlU7z7yw8UpcJA/jOl\r\n' + +'NWu7eS9uzuckdVZ9FE0+x3DRvhtDI6K+18dcrUWtl5ADWXcs1QS3/7bGh7IybFyY\r\n' + +'0xT4VzLHcx6K4PNmfkjAQdyOz/EsuRqZ/ngIQ2tdHdkkzdQPECbTvFeG2wIDAQAB\r\n' + +'AoGAds3l7l2QHaxo7GzfqNBMXEdwto2tLxS8C6eQ+pkkBXm72HcF+Vj75AcTMD2p\r\n' + +'fwZYXQxHdV4yqRI+fZeku7uTA/3yBAAvNobbEN5jtHnq0ZTO/HO8HuHkKrCvD8c3\r\n' + +'0rJV6lNIuaARI9jZFf6HVchW3PMjKUpYhTs/sFhRxmsMpTkCQQDu8TPzXRmN1aw8\r\n' + +'tSI2Nyn8QUy9bw/12tlVaZIhrcVCiJl7JHGqSCowTqZlwmJIjd4W0zWjTvS7tEeO\r\n' + +'FaZHtP8lAkEAniGvm8S9zyzmhWRRIuU6EE2dtTbeAa5aSOK3nBaaNu2cHUxWle+J\r\n' + +'8lE4uequ9wqDG1AfOLobPmHReccmOI6N/wJAIP/I1/RkohT/a4bsiaZGsyLlkUf0\r\n' + +'YVTvLP+ege44zv6Ei+A1nnnG8dL64hTdc/27zVUwFDTEUeQM+c99nmudzQJBAApY\r\n' + +'qeTHOqQTjAGuTqC53tKyQV9Z96yke8PJEbpkwDJX2Z8RH5kv0xbHua5wbII9bdab\r\n' + +'p29OvfmW7N3K6fVJXoECQHK8FDC0i8v1Ui8FoBmt+Z1c1+/9TCEE0abUQ6rfOUbm\r\n' + +'XHMMac/n4qDs0OoCjR4u46dpoK+WN7zcg56tToFPVow=\r\n' + +'-----END RSA PRIVATE KEY-----'; + var certificate = + '-----BEGIN CERTIFICATE-----\r\n' + +'MIICgDCCAemgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMRMwEQYDVQQDEwpKb2hu\r\n' + +'IFNtaXRoMRMwEQYDVQQHEwpCbGFja3NidXJnMREwDwYDVQQIEwhWaXJnaW5pYTEL\r\n' + +'MAkGA1UEBhMCVVMxDDAKBgNVBAoTA0ZvbzAeFw0xMDExMjYxNzUxMzJaFw0xMTEx\r\n' + +'MjYxNzUxMzJaMFgxEzARBgNVBAMTCkpvaG4gU21pdGgxEzARBgNVBAcTCkJsYWNr\r\n' + +'c2J1cmcxETAPBgNVBAgTCFZpcmdpbmlhMQswCQYDVQQGEwJVUzEMMAoGA1UEChMD\r\n' + +'Rm9vMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCTmE8QLARsC57Z1OrOaLM6\r\n' + +'AS3fn70N7BvlU7z7yw8UpcJA/jOlNWu7eS9uzuckdVZ9FE0+x3DRvhtDI6K+18dc\r\n' + +'rUWtl5ADWXcs1QS3/7bGh7IybFyY0xT4VzLHcx6K4PNmfkjAQdyOz/EsuRqZ/ngI\r\n' + +'Q2tdHdkkzdQPECbTvFeG2wIDAQABo1owWDAMBgNVHRMEBTADAQH/MAsGA1UdDwQE\r\n' + +'AwIC9DA7BgNVHREENDAyhjBodHRwOi8vd2ViaWQuZGlnaXRhbGJhemFhci5jb20v\r\n' + +'aWRzLzE1MzQ1NzI2NDcjbWUwDQYJKoZIhvcNAQEFBQADgYEAPNm8albI4w6anynw\r\n' + +'XE/+00sCVks9BbgTcIpRqZPGqSuTRwoYW35isNLDqFqIUdVREMvFrEn3nOlOyKi0\r\n' + +'29G8JtLHFSXZsqf38Zou/bGAhtEH1AVEbM2bRtEnG8IW24jL8hiciz4htxmjnkHN\r\n' + +'JnQ8SQtUSWplGnz0vMFEOv6JbnI=\r\n' + +'-----END CERTIFICATE-----'; + + // create websocket + var ws = new WebSocket('ws://' + host + ':' + port); + forge.log.debug(cat, 'Created WebSocket', ws); + + // create TLS client + var success = false; + var tls = forge.tls.createConnection( + { + server: false, + caStore: [], + sessionCache: {}, + // supported cipher suites in order of preference + cipherSuites: [ + forge.tls.CipherSuites.TLS_RSA_WITH_AES_128_CBC_SHA, + forge.tls.CipherSuites.TLS_RSA_WITH_AES_256_CBC_SHA], + virtualHost: host, + verify: function(c, verified, depth, certs) + { + forge.log.debug(cat, + 'TLS Client verifying certificate w/CN: \"' + + certs[0].subject.getField('CN').value + '\"'); + // accept any certificate from the server for this test + return true; + }, + connected: function(c) + { + forge.log.debug(cat, 'Client connected'); + }, + getCertificate: function(c, hint) + { + forge.log.debug(cat, 'Client using client-certificate'); + return certificate; + }, + getPrivateKey: function(c, cert) + { + return privateKey; + }, + tlsDataReady: function(c) + { + // send base64-encoded TLS data to server + ws.send(forge.util.encode64(c.tlsData.getBytes())); + }, + dataReady: function(c) + { + var response = c.data.getBytes(); + forge.log.debug(cat, 'Client received \"' + response + '\"'); + try + { + response = JSON.parse(response); + success = response.success; + + // TODO: call window.authenticate on response json, just like + // w/flash version + } + catch(ex) {} + c.close(); + }, + closed: function(c) + { + forge.log.debug(cat, 'Client disconnected'); + if(success) + { + forge.log.debug(cat, 'PASS'); + } + else + { + forge.log.debug(cat, 'FAIL'); + } + }, + error: function(c, error) + { + forge.log.debug(cat, 'Client error: ' + error.message); + } + }); + + ws.onopen = function(evt) + { + forge.log.debug(cat, 'WebSocket connected'); + + // do TLS handshake + tls.handshake(); + }; + ws.onmessage = function(evt) + { + // base64-decode data and process it + tls.process(forge.util.decode64(evt.data)); + }; + ws.onclose = function(evt) + { + forge.log.debug(cat, 'WebSocket closed'); + }; +}; + diff --git a/school/node_modules/node-forge/tests/ws.js b/school/node_modules/node-forge/tests/ws.js new file mode 100644 index 0000000..ba0b39d --- /dev/null +++ b/school/node_modules/node-forge/tests/ws.js @@ -0,0 +1,237 @@ +// Github: http://github.com/ncr/node.ws.js +// Compatible with node v0.1.91 +// Author: Jacek Becela +// Contributors: +// Michael Stillwell http://github.com/ithinkihaveacat +// Nick Chapman http://github.com/nchapman +// Dmitriy Shalashov http://github.com/skaurus +// Johan Dahlberg +// Andreas Kompanez +// Samuel Cyprian http://github.com/samcyp +// License: MIT +// Based on: http://github.com/Guille/node.websocket.js + +function nano(template, data) { + return template.replace(/\{([\w\.]*)}/g, function (str, key) { + var keys = key.split("."), value = data[keys.shift()]; + keys.forEach(function (key) { value = value[key];}); + return value; + }); +} + +function pack(num) { + var result = ''; + result += String.fromCharCode(num >> 24 & 0xFF); + result += String.fromCharCode(num >> 16 & 0xFF); + result += String.fromCharCode(num >> 8 & 0xFF); + result += String.fromCharCode(num & 0xFF); + return result; +} + +var sys = require("sys"), + net = require("net"), + crypto = require("crypto"), + requiredHeaders = { + 'get': /^GET (\/[^\s]*)/, + 'upgrade': /^WebSocket$/, + 'connection': /^Upgrade$/, + 'host': /^(.+)$/, + 'origin': /^(.+)$/ + }, + handshakeTemplate75 = [ + 'HTTP/1.1 101 Web Socket Protocol Handshake', + 'Upgrade: WebSocket', + 'Connection: Upgrade', + 'WebSocket-Origin: {origin}', + 'WebSocket-Location: {protocol}://{host}{resource}', + '', + '' + ].join("\r\n"), + handshakeTemplate76 = [ + 'HTTP/1.1 101 WebSocket Protocol Handshake', // note a diff here + 'Upgrade: WebSocket', + 'Connection: Upgrade', + 'Sec-WebSocket-Origin: {origin}', + 'Sec-WebSocket-Location: {protocol}://{host}{resource}', + '', + '{data}' + ].join("\r\n"), + flashPolicy = '<cross-domain-policy><allow-access-from domain="*" to-ports="*" /></cross-domain-policy>'; + + + +exports.createSecureServer = function (websocketListener, credentials, options) { + if (!options) options = {}; + options.secure = credentials; + return this.createServer(websocketListener, options); +}; + +exports.createServer = function (websocketListener, options) { + if (!options) options = {}; + if (!options.flashPolicy) options.flashPolicy = flashPolicy; + // The value should be a crypto credentials + if (!options.secure) options.secure = null; + + return net.createServer(function (socket) { + //Secure WebSockets + var wsProtocol = 'ws'; + if(options.secure) { + wsProtocol = 'wss'; + socket.setSecure(options.secure); + } + socket.setTimeout(0); + socket.setNoDelay(true); + socket.setKeepAlive(true, 0); + + var emitter = new process.EventEmitter(), + handshaked = false, + buffer = ""; + + function handle(data) { + buffer += data; + + var chunks = buffer.split("\ufffd"), + count = chunks.length - 1; // last is "" or a partial packet + + for(var i = 0; i < count; i++) { + var chunk = chunks[i]; + if(chunk[0] == "\u0000") { + emitter.emit("data", chunk.slice(1)); + } else { + socket.end(); + return; + } + } + + buffer = chunks[count]; + } + + function handshake(data) { + var _headers = data.split("\r\n"); + + if ( /<policy-file-request.*>/.exec(_headers[0]) ) { + socket.write( options.flashPolicy ); + socket.end(); + return; + } + + // go to more convenient hash form + var headers = {}, upgradeHead, len = _headers.length; + if ( _headers[0].match(/^GET /) ) { + headers["get"] = _headers[0]; + } else { + socket.end(); + return; + } + if ( _headers[ _headers.length - 1 ] ) { + upgradeHead = _headers[ _headers.length - 1 ]; + len--; + } + while (--len) { // _headers[0] will be skipped + var header = _headers[len]; + if (!header) continue; + + var split = header.split(": ", 2); // second parameter actually seems to not work in node + headers[ split[0].toLowerCase() ] = split[1]; + } + + // check if we have all needed headers and fetch data from them + var data = {}, match; + for (var header in requiredHeaders) { + // regexp actual header value + if ( match = requiredHeaders[ header ].exec( headers[header] ) ) { + data[header] = match; + } else { + socket.end(); + return; + } + } + + // draft auto-sensing + if ( headers["sec-websocket-key1"] && headers["sec-websocket-key2"] && upgradeHead ) { // 76 + var strkey1 = headers["sec-websocket-key1"] + , strkey2 = headers["sec-websocket-key2"] + + , numkey1 = parseInt(strkey1.replace(/[^\d]/g, ""), 10) + , numkey2 = parseInt(strkey2.replace(/[^\d]/g, ""), 10) + + , spaces1 = strkey1.replace(/[^\ ]/g, "").length + , spaces2 = strkey2.replace(/[^\ ]/g, "").length; + + if (spaces1 == 0 || spaces2 == 0 || numkey1 % spaces1 != 0 || numkey2 % spaces2 != 0) { + socket.end(); + return; + } + + var hash = crypto.createHash("md5") + , key1 = pack(parseInt(numkey1/spaces1)) + , key2 = pack(parseInt(numkey2/spaces2)); + + hash.update(key1); + hash.update(key2); + hash.update(upgradeHead); + + socket.write(nano(handshakeTemplate76, { + protocol: wsProtocol, + resource: data.get[1], + host: data.host[1], + origin: data.origin[1], + data: hash.digest("binary") + }), "binary"); + + } else { // 75 + socket.write(nano(handshakeTemplate75, { + protocol: wsProtocol, + resource: data.get[1], + host: data.host[1], + origin: data.origin[1] + })); + + } + + handshaked = true; + emitter.emit("connect", data.get[1]); + } + + socket.addListener("data", function (data) { + if(handshaked) { + handle(data.toString("utf8")); + } else { + handshake(data.toString("binary")); // because of draft76 handshakes + } + }).addListener("end", function () { + socket.end(); + }).addListener("close", function () { + if (handshaked) { // don't emit close from policy-requests + emitter.emit("close"); + } + }).addListener("error", function (exception) { + if (emitter.listeners("error").length > 0) { + emitter.emit("error", exception); + } else { + throw exception; + } + }); + + emitter.remoteAddress = socket.remoteAddress; + + emitter.write = function (data) { + try { + socket.write('\u0000', 'binary'); + socket.write(data, 'utf8'); + socket.write('\uffff', 'binary'); + } catch(e) { + // Socket not open for writing, + // should get "close" event just before. + socket.end(); + } + }; + + emitter.end = function () { + socket.end(); + }; + + websocketListener(emitter); // emits: "connect", "data", "close", provides: write(data), end() + }); +}; + diff --git a/school/node_modules/node-forge/tests/xhr.html b/school/node_modules/node-forge/tests/xhr.html new file mode 100644 index 0000000..aaa721c --- /dev/null +++ b/school/node_modules/node-forge/tests/xhr.html @@ -0,0 +1,87 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head> + <title>Forge XmlHttpRequest Test</title> + <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js"></script> + <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script> + <script type="text/javascript" src="forge/debug.js"></script> + <script type="text/javascript" src="forge/util.js"></script> + <script type="text/javascript" src="forge/log.js"></script> + <script type="text/javascript" src="forge/task.js"></script> + <script type="text/javascript" src="forge/socket.js"></script> + <script type="text/javascript" src="forge/md5.js"></script> + <script type="text/javascript" src="forge/sha1.js"></script> + <script type="text/javascript" src="forge/hmac.js"></script> + <script type="text/javascript" src="forge/aes.js"></script> + <script type="text/javascript" src="forge/pem.js"></script> + <script type="text/javascript" src="forge/asn1.js"></script> + <script type="text/javascript" src="forge/jsbn.js"></script> + <script type="text/javascript" src="forge/prng.js"></script> + <script type="text/javascript" src="forge/random.js"></script> + <script type="text/javascript" src="forge/oids.js"></script> + <script type="text/javascript" src="forge/rsa.js"></script> + <script type="text/javascript" src="forge/pbe.js"></script> + <script type="text/javascript" src="forge/x509.js"></script> + <script type="text/javascript" src="forge/pki.js"></script> + <script type="text/javascript" src="forge/tls.js"></script> + <script type="text/javascript" src="forge/aesCipherSuites.js"></script> + <script type="text/javascript" src="forge/tlssocket.js"></script> + <script type="text/javascript" src="forge/http.js"></script> + <script type="text/javascript" src="forge/xhr.js"></script> + <script type="text/javascript" src="xhr.js"></script> + + <link type="text/css" rel="stylesheet" media="all" href="screen.css" /> + <style type="text/css"> + .ready { color: inherit; background: inherit; } + .testing { color: black; background: yellow; } + .pass{ color: white; background: green; } + .fail{ color: white; background: red; } + </style> + </head> +<body> +<div class="nav"><a href="index.html">Forge Tests</a> / XHR</div> + +<div class="header"> + <h1>XmlHttpRequest Tests</h1> +</div> + +<div class="content"> + +<!-- div used to hold the flash socket pool implemenation --> +<div id="socketPool"> + <p>Could not load the flash SocketPool.</p> +</div> + +<fieldset class="section"> + <ul> + <li>Use the controls below to test the XHR wrapper.</li> + </ul> +</fieldset> + +<fieldset class="section"> +<legend>Control</legend> + <button id="start">Start</button> + <button id="reset">Reset</button> + <br/> + <input id="scroll" type="checkbox" checked="checked" />Scroll Tests + <br/> + <button id="stress">Stress</button> +</fieldset> + +<fieldset class="section"> +<legend>Progress</legend> +Status: <span id="status">?</span><br/> +Pass: <span id="pass">?</span>/<span id="total">?</span><br/> +Fail: <span id="fail">?</span> +</fieldset> + +<fieldset class="section"> +<legend>Tests</legend> +<div id="tests"></div> +</fieldset> + +</div> +</body> +</html> diff --git a/school/node_modules/node-forge/tests/xhr.js b/school/node_modules/node-forge/tests/xhr.js new file mode 100644 index 0000000..78f91ad --- /dev/null +++ b/school/node_modules/node-forge/tests/xhr.js @@ -0,0 +1,590 @@ +/** + * Forge XmlHttpRequest Test + * + * @author Dave Longley + * @author David I. Lehn <dlehn@digitalbazaar.com> + * + * Copyright (c) 2009-2010 Digital Bazaar, Inc. All rights reserved. + */ +(function($) +{ + // load flash socket pool + window.forge.socketPool = {}; + window.forge.socketPool.ready = function() + { + // init forge xhr + forge.xhr.init({ + flashId: 'socketPool', + policyPort: 19945, + msie: $.browser.msie, + connections: 10, + caCerts: [], + verify: function(c, verified, depth, certs) + { + // don't care about cert verification for test + return true; + } + }); + }; + swfobject.embedSWF( + 'forge/SocketPool.swf', 'socketPool', '0', '0', '9.0.0', + false, {}, {allowscriptaccess: 'always'}, {}); +})(jQuery); + +jQuery(function($) +{ + var cat = 'forge.tests.xhr'; + + var tests = []; + var passed = 0; + var failed = 0; + + var init = function() { + passed = failed = 0; + $('.ready,.testing,.pass,.fail') + .removeClass('ready testing pass fail'); + $('#status') + .text('Ready.') + .addClass('ready'); + $('#total').text(tests.length); + $('#pass').text(passed); + $('#fail').text(failed); + $('.expect').empty(); + $('.result').empty(); + $('.time').empty(); + $('.timePer').empty(); + $('#start').removeAttr('disabled'); + }; + + var start = function() + { + $('#start').attr('disabled', 'disabled'); + // meta! use tasks to run the task tests + forge.task.start({ + type: 'test', + run: function(task) { + task.next('starting', function(task) { + forge.log.debug(cat, 'start'); + $('#status') + .text('Testing...') + .addClass('testing') + .removeClass('idle'); + }); + $.each(tests, function(i, test) { + task.next('test', function(task) { + var title = $('li:first', test.container); + if($('#scroll:checked').length === 1) + { + $('html,body').animate({scrollTop: title.offset().top}); + } + title.addClass('testing'); + test.run(task, test); + }); + task.next('test', function(task) { + $('li:first', test.container).removeClass('testing'); + }); + }); + task.next('success', function(task) { + forge.log.debug(cat, 'done'); + if(failed === 0) { + $('#status') + .text('PASS') + .addClass('pass') + .removeClass('testing'); + } else { + // FIXME: should just be hitting failure() below + $('#status') + .text('FAIL') + .addClass('fail') + .removeClass('testing'); + } + }); + }, + failure: function() { + $('#status') + .text('FAIL') + .addClass('fail') + .removeClass('testing'); + } + }); + }; + + $('#start').click(function() { + start(); + }); + + $('#reset').click(function() { + init(); + }); + + var stressStats = + { + sent: 0, + success: 0, + error: 0 + }; + var stressStatsMessage = function() + { + return 'received:' + (stressStats.success + stressStats.error) + '/' + + stressStats.sent + ' errors:' + stressStats.error; + }; + + $('#stress').click(function() { + for(var i = 1; i <= 100; ++i) + { + (function(seqnum) + { + setTimeout(function() + { + $.ajax( + { + type: 'GET', + url: '/result.txt?seq=' + seqnum, + beforeSend: function(xhr) + { + ++stressStats.sent; + xhr.setRequestHeader('Connection', 'close'); + }, + success: function(data, textStatus, xhr) + { + ++stressStats.success; + forge.log.debug(cat, 'xhr connection completed' + + ' seq:' + seqnum + + ' datalen:' + data.length + ' ' + + stressStatsMessage()); + }, + error: function(xhr, textStatus, errorThrown) + { + ++stressStats.error; + forge.log.error(cat, 'xhr connection failed' + + ' seq:' + seqnum + ' ' + + stressStatsMessage(), arguments); + }, + xhr: forge.xhr.create + }); + }, 0); + })(i); + } + return false; + }); + + /** + * Creates a simple XMLHttpRequest wrapper. For testing. + */ + var createWrapper = function() + { + var UNSENT = 0; + var OPENED = 1; + var HEADERS_RECEIVED = 2; + var LOADING = 3; + var DONE = 4; + + var toWrap = new XMLHttpRequest(); + + // create xhr wrapper object + var xhr = + { + // FIXME: an EventListener + onreadystatechange: null, + // FIXME: readonly + readyState: UNSENT, + // FIXME: a string + responseText: null, + // FIXME: a document + responseXML: null, + // FIXME: readonly, returns the HTTP status code + status: 0, + // FIXME: readonly, returns the HTTP status message + statusText: null, + + // FIXME: async, user, and password are optional + open: function(method, url, async, user, password) + { + toWrap.open(method, url, async, user, password); + }, + + setRequestHeader: function(header, value) + { + toWrap.setRequestHeader(header, value); + }, + + // FIXME: data can be a string or a document + send: function(data) + { + toWrap.send(data); + }, + + abort: function() + { + toWrap.abort(); + toWrap.onreadystatechange = null; + toWrap = null; + }, + + // FIXME: return all response headers as a string + getAllResponseHeaders: function() + { + return toWrap.getAllResponseHeaders(); + }, + + // FIXME: return header field value + getResponseHeader: function(header) + { + return toWrap.getResponseHeader(header); + } + }; + + toWrap.onreadystatechange = function() + { + // copy attributes + xhr.readyState = toWrap.readyState; + xhr.responseText = toWrap.responseText; + xhr.responseXML = toWrap.responseXML; + + if(toWrap.readyState == HEADERS_RECEIVED) + { + xhr.status = toWrap.status; + xhr.statusText = toWrap.statusText; + } + + if(xhr.onreadystatechange) + { + //forge.log.debug(cat, 'wrapper orsc', toWrap); + xhr.onreadystatechange(); + } + }; + + return xhr; + }; + + var addTest = function(name, run) + { + var container = $('<ul><li>Test ' + name + '</li><ul/></ul>'); + var expect = $('<li>Expect: <span class="expect"/></li>'); + var result = $('<li>Result: <span class="result"/></li>'); + var time = $('<li>Time: <span class="time"/></li>'); + var timePer = $('<li>Time Per Iteration: <span class="timePer"/></li>'); + $('ul', container) + .append(expect) + .append(result) + .append(time) + .append(timePer); + $('#tests').append(container); + var test = { + container: container, + startTime: null, + run: function(task, test) { + test.startTime = new Date(); + run(task, test); + }, + expect: $('span', expect), + result: $('span', result), + check: function() { + var e = test.expect.text(); + var r = test.result.text(); + (e == r) ? test.pass() : test.fail(); + }, + pass: function(iterations) { + var dt = new Date() - test.startTime; + if(!iterations) + { + iterations = 1; + } + var dti = (dt / iterations); + passed += 1; + $('#pass').text(passed); + $('li:first', container).addClass('pass'); + $('span.time', container).html(dt + 'ms'); + $('span.timePer', container).html(dti + 'ms'); + }, + fail: function(iterations) { + var dt = new Date() - test.startTime; + if(!iterations) + { + iterations = 1; + } + var dti = (dt / iterations); + failed += 1; + $('#fail').text(failed); + $('li:first', container).addClass('fail'); + $('span.time', container).html(dt + 'ms'); + $('span.timePer', container).html(dti + 'ms'); + } + }; + tests.push(test); + }; + + addTest('builtin xhr', function(task, test) + { + task.block(); + + $.ajax( + { + type: 'GET', + url: '/result.txt', + success: function(data) + { + test.expect.html('expected result'); + test.result.html(data); + task.unblock(); + }, + error: function() + { + task.fail(); + } + }); + + task.next(function(task) + { + test.pass(); + }); + }); + + addTest('builtin xhr (10 serial)', function(task, test) + { + var N = 10; + for(var i = 0; i < N; i++) + { + task.next(function(task) + { + task.parent.block(); + + $.ajax( + { + type: 'GET', + url: '/result.txt', + success: function(data, textStatus) + { + test.result.append('.'); + task.parent.unblock(); + }, + error: function(xhr, textStatus, errorThrown) + { + task.fail(N); + } + }); + }); + } + + task.next(function(task) + { + test.pass(N); + }); + }); + + addTest('builtin xhr (10 parallel)', function(task, test) + { + var N = 10; + task.block(N); + for(var i = 0; i < N; i++) + { + $.ajax( + { + type: 'GET', + url: '/result.txt', + success: function(data, textStatus) + { + test.result.append('.'); + task.unblock(); + }, + error: function(xhr, textStatus, errorThrown) + { + task.fail(N); + } + }); + } + + task.next(function(task) + { + test.pass(N); + }); + }); + + // test only works with non-IE + if(!$.browser.msie) + { + addTest('generic wrapper xhr', function(task, test) + { + task.block(); + + $.ajax( + { + type: 'GET', + url: '/result.txt', + success: function(data) + { + test.expect.html('expected result'); + test.result.html(data); + task.unblock(); + }, + error: function() + { + task.fail(); + }, + xhr: createWrapper + }); + + task.next(function(task) + { + test.pass(); + }); + }); + + addTest('generic wrapper xhr (10 serial)', function(task, test) + { + var N = 10; + for(var i = 0; i < N; i++) + { + task.next(function(task) + { + task.parent.block(); + + $.ajax( + { + type: 'GET', + url: '/result.txt', + success: function(data, textStatus) + { + test.result.append('.'); + task.parent.unblock(); + }, + error: function(xhr, textStatus, errorThrown) + { + task.fail(N); + }, + xhr: createWrapper + }); + }); + } + + task.next(function(task) + { + test.pass(N); + }); + }); + + addTest('generic wrapper xhr (10 parallel)', function(task, test) + { + var N = 10; + task.block(N); + for(var i = 0; i < N; i++) + { + $.ajax( + { + type: 'GET', + url: '/result.txt', + success: function(data, textStatus) + { + test.result.append('.'); + task.unblock(); + }, + error: function(xhr, textStatus, errorThrown) + { + task.fail(N); + }, + xhr: createWrapper + }); + } + + task.next(function(task) + { + test.pass(N); + }); + }); + } + + for(var i = 0; i < 3; i++) { + addTest('TLS xhr ' + i, function(task, test) + { + task.block(); + + $.ajax( + { + type: 'GET', + url: '/result.txt', + success: function(data, textStatus, xhr) + { + test.expect.html('expected result'); + test.result.html(data); + task.unblock(); + }, + error: function(xhr, textStatus, errorThrown) + { + task.fail(); + }, + xhr: forge.xhr.create + }); + + task.next(function(task) + { + test.pass(); + }); + }); + } + + addTest('TLS xhr (10 serial)', function(task, test) + { + var N = 10; + for(var i = 0; i < N; i++) + { + task.next(function(task) + { + task.parent.block(); + + $.ajax( + { + type: 'GET', + url: '/result.txt', + success: function(data, textStatus, xhr) + { + test.result.append('.'); + task.parent.unblock(); + }, + error: function(xhr, textStatus, errorThrown) + { + task.fail(N); + }, + xhr: forge.xhr.create + }); + }); + } + + task.next(function(task) + { + test.pass(N); + }); + }); + + addTest('TLS xhr (10 parallel) ' + + '(hit "Reset" then "Start" to speed up - uses SSL session cache)', + function(task, test) + { + var N = 10; + task.block(N); + for(var i = 0; i < N; i++) + { + $.ajax( + { + type: 'GET', + url: '/result.txt', + success: function(data, textStatus, xhr) + { + test.result.append('.'); + task.unblock(); + }, + error: function(xhr, textStatus, errorThrown) + { + task.fail(N); + }, + xhr: forge.xhr.create + }); + } + + task.next(function(task) + { + test.pass(N); + }); + }); + + init(); +}); |