diff --git a/app.js b/app.js
index f2066dd..22e293a 100644
--- a/app.js
+++ b/app.js
@@ -2,6 +2,9 @@
   'use strict';
 
   var Keypairs = window.Keypairs;
+  var Rasha = window.Rasha;
+  var Eckles = window.Eckles;
+  var x509 = window.x509;
 
   function $(sel) {
     return document.querySelector(sel);
@@ -35,9 +38,10 @@
       $('.js-loading').hidden = false;
       $('.js-jwk').hidden = true;
       $('.js-toc-der-public').hidden = true;
-      $('.js-toc-pem-public').hidden = true;
       $('.js-toc-der-private').hidden = true;
-      $('.js-toc-pem-private').hidden = true;
+      $$('.js-toc-pem').forEach(function ($el) {
+        $el.hidden = true;
+      });
       $$('input').map(function ($el) { $el.disabled = true; });
       $$('button').map(function ($el) { $el.disabled = true; });
       var opts = {
@@ -47,32 +51,47 @@
       };
       console.log('opts', opts);
       Keypairs.generate(opts).then(function (results) {
-        var der_public, der_private;
-        if (opts.kty == 'EC') {
-          der_public = x509.packSpki(results.public);
-          der_private = x509.packPkcs8(results.private);
-          var pem_private = Eckles.export({ jwk: results.private })
-          var pem_public = Eckles.export({ jwk: results.public, public: true })
-          $('.js-input-pem-public').innerText = pem_public;
-          $('.js-toc-pem-public').hidden = false;
-          $('.js-input-pem-private').innerText = pem_private;
-          $('.js-toc-pem-private').hidden = false;
+        var pubDer;
+        var privDer;
+        if (/EC/i.test(opts.kty)) {
+          privDer = x509.packPkcs8(results.private);
+          pubDer = x509.packSpki(results.public);
+          Eckles.export({ jwk: results.private, format: 'sec1' }).then(function (pem) {
+            $('.js-input-pem-sec1-private').innerText = pem;
+            $('.js-toc-pem-sec1-private').hidden = false;
+          });
+          Eckles.export({ jwk: results.private, format: 'pkcs8' }).then(function (pem) {
+            $('.js-input-pem-pkcs8-private').innerText = pem;
+            $('.js-toc-pem-pkcs8-private').hidden = false;
+          });
+          Eckles.export({ jwk: results.public, public: true }).then(function (pem) {
+            $('.js-input-pem-spki-public').innerText = pem;
+            $('.js-toc-pem-spki-public').hidden = false;
+          });
         } else {
-          der_private = x509.packPkcs8(results.private);
-          der_public = x509.packPkcs8(results.public);
-          Rasha.pack({ jwk: results.private }).then(function (pem) {
-            $('.js-input-pem-private').innerText = pem;
-            $('.js-toc-pem-private').hidden = false;
-          })
-          Rasha.pack({ jwk: results.public }).then(function (pem) {
-            $('.js-input-pem-public').innerText = pem;
-            $('.js-toc-pem-public').hidden = false;
-          })
+          privDer = x509.packPkcs8(results.private);
+          pubDer = x509.packSpki(results.public);
+          Rasha.export({ jwk: results.private, format: 'pkcs1' }).then(function (pem) {
+            $('.js-input-pem-pkcs1-private').innerText = pem;
+            $('.js-toc-pem-pkcs1-private').hidden = false;
+          });
+          Rasha.export({ jwk: results.private, format: 'pkcs8' }).then(function (pem) {
+            $('.js-input-pem-pkcs8-private').innerText = pem;
+            $('.js-toc-pem-pkcs8-private').hidden = false;
+          });
+          Rasha.export({ jwk: results.public, format: 'pkcs1' }).then(function (pem) {
+            $('.js-input-pem-pkcs1-public').innerText = pem;
+            $('.js-toc-pem-pkcs1-public').hidden = false;
+          });
+          Rasha.export({ jwk: results.public, format: 'spki' }).then(function (pem) {
+            $('.js-input-pem-spki-public').innerText = pem;
+            $('.js-toc-pem-spki-public').hidden = false;
+          });
         }
 
-        $('.js-der-public').innerText = der_public;
+        $('.js-der-public').innerText = pubDer;
         $('.js-toc-der-public').hidden = false;
-        $('.js-der-private').innerText = der_private;
+        $('.js-der-private').innerText = privDer;
         $('.js-toc-der-private').hidden = false;
         $('.js-jwk').innerText = JSON.stringify(results, null, 2);
         $('.js-loading').hidden = true;
@@ -87,7 +106,7 @@
       ev.preventDefault();
       ev.stopPropagation();
       $('.js-loading').hidden = false;
-      ACME.accounts.create
+      //ACME.accounts.create
     });
 
     $('.js-generate').hidden = false;
diff --git a/index.html b/index.html
index 047936b..013e3b4 100644
--- a/index.html
+++ b/index.html
@@ -8,10 +8,10 @@
       }
       /* need to word wrap the binary no space der */
       .js-der-public, .js-der-private{
-        white-space: pre-wrap;      /* CSS3 */   
-        white-space: -moz-pre-wrap; /* Firefox */    
-        white-space: -pre-wrap;     /* Opera <7 */   
-        white-space: -o-pre-wrap;   /* Opera 7 */    
+        white-space: pre-wrap;      /* CSS3 */
+        white-space: -moz-pre-wrap; /* Firefox */
+        white-space: -pre-wrap;     /* Opera <7 */
+        white-space: -o-pre-wrap;   /* Opera 7 */
         word-wrap: break-word;      /* IE */
       }
     
@@ -80,13 +80,25 @@
       DER Public Binary
       
 
     
-    
-      PEM Private (base64-encoded DER)
-      
+    
+      PEM Private (base64-encoded PKCS1 DER)
+      
      
-    
-      PEM Public (base64-encoded DER)
-      
+    
+      PEM Private (base64-encoded SEC1 DER)
+      
+     
+    
+      PEM Private (base64-encoded PKCS8 DER)
+      
+     
+    
+      PEM Public (base64-encoded PKCS1 DER)
+      
+     
+    
+      PEM Public (base64-encoded SPKI/PKIX DER)
+      
      
     
       ACME Account Request
@@ -97,9 +109,9 @@
        
      
     
-    
     
     
+    
     
     
     
diff --git a/lib/ecdsa.js b/lib/ecdsa.js
index deb2c86..eff9794 100644
--- a/lib/ecdsa.js
+++ b/lib/ecdsa.js
@@ -3,7 +3,10 @@
 'use strict';
 
 var EC = exports.Eckles = {};
+var x509 = exports.x509;
 if ('undefined' !== typeof module) { module.exports = EC; }
+var PEM = exports.PEM;
+var SSH = exports.SSH;
 var Enc = {};
 var textEncoder = new TextEncoder();
 
@@ -32,7 +35,7 @@ EC.generate = function (opts) {
       + " Please choose either 'P-256' or 'P-384'. "
       + EC._stance));
   }
-  
+
   var extractable = true;
   return window.crypto.subtle.generateKey(
     wcOpts
@@ -52,51 +55,53 @@ EC.generate = function (opts) {
 };
 
 EC.export = function (opts) {
-  if (!opts || !opts.jwk || 'object' !== typeof opts.jwk) {
-    throw new Error("must pass { jwk: jwk } as a JSON object");
-  }
-  var jwk = JSON.parse(JSON.stringify(opts.jwk));
-  var format = opts.format;
-  if (opts.public || -1 !== [ 'spki', 'pkix', 'ssh', 'rfc4716' ].indexOf(format)) {
-    jwk.d = null;
-  }
-  if ('EC' !== jwk.kty) {
-    throw new Error("options.jwk.kty must be 'EC' for EC keys");
-  }
-  if (!jwk.d) {
-    if (!format || -1 !== [ 'spki', 'pkix' ].indexOf(format)) {
-      format = 'spki';
-    } else if (-1 !== [ 'ssh', 'rfc4716' ].indexOf(format)) {
-      format = 'ssh';
+  return Promise.resolve().then(function () {
+    if (!opts || !opts.jwk || 'object' !== typeof opts.jwk) {
+      throw new Error("must pass { jwk: jwk } as a JSON object");
+    }
+    var jwk = JSON.parse(JSON.stringify(opts.jwk));
+    var format = opts.format;
+    if (opts.public || -1 !== [ 'spki', 'pkix', 'ssh', 'rfc4716' ].indexOf(format)) {
+      jwk.d = null;
+    }
+    if ('EC' !== jwk.kty) {
+      throw new Error("options.jwk.kty must be 'EC' for EC keys");
+    }
+    if (!jwk.d) {
+      if (!format || -1 !== [ 'spki', 'pkix' ].indexOf(format)) {
+        format = 'spki';
+      } else if (-1 !== [ 'ssh', 'rfc4716' ].indexOf(format)) {
+        format = 'ssh';
+      } else {
+        throw new Error("options.format must be 'spki' or 'ssh' for public EC keys, not ("
+          + typeof format + ") " + format);
+      }
     } else {
-      throw new Error("options.format must be 'spki' or 'ssh' for public EC keys, not ("
-        + typeof format + ") " + format);
+      if (!format || 'sec1' === format) {
+        format = 'sec1';
+      } else if ('pkcs8' !== format) {
+        throw new Error("options.format must be 'sec1' or 'pkcs8' for private EC keys, not '" + format + "'");
+      }
     }
-  } else {
-    if (!format || 'sec1' === format) {
-      format = 'sec1';
-    } else if ('pkcs8' !== format) {
-      throw new Error("options.format must be 'sec1' or 'pkcs8' for private EC keys, not '" + format + "'");
+    if (-1 === [ 'P-256', 'P-384' ].indexOf(jwk.crv)) {
+      throw new Error("options.jwk.crv must be either P-256 or P-384 for EC keys, not '" + jwk.crv + "'");
+    }
+    if (!jwk.y) {
+      throw new Error("options.jwk.y must be a urlsafe base64-encoded either P-256 or P-384");
     }
-  }
-  if (-1 === [ 'P-256', 'P-384' ].indexOf(jwk.crv)) {
-    throw new Error("options.jwk.crv must be either P-256 or P-384 for EC keys, not '" + jwk.crv + "'");
-  }
-  if (!jwk.y) {
-    throw new Error("options.jwk.y must be a urlsafe base64-encoded either P-256 or P-384");
-  }
 
-  if ('sec1' === format) {
-    return PEM.packBlock({ type: "EC PRIVATE KEY", bytes: x509.packSec1(jwk) });
-  } else if ('pkcs8' === format) {
-    return PEM.packBlock({ type: "PRIVATE KEY", bytes: x509.packPkcs8(jwk) });
-  } else if (-1 !== [ 'spki', 'pkix' ].indexOf(format)) {
-    return PEM.packBlock({ type: "PUBLIC KEY", bytes: x509.packSpki(jwk) });
-  } else if (-1 !== [ 'ssh', 'rfc4716' ].indexOf(format)) {
-    return SSH.packSsh(jwk);
-  } else {
-    throw new Error("Sanity Error: reached unreachable code block with format: " + format);
-  }
+    if ('sec1' === format) {
+      return PEM.packBlock({ type: "EC PRIVATE KEY", bytes: x509.packSec1(jwk) });
+    } else if ('pkcs8' === format) {
+      return PEM.packBlock({ type: "PRIVATE KEY", bytes: x509.packPkcs8(jwk) });
+    } else if (-1 !== [ 'spki', 'pkix' ].indexOf(format)) {
+      return PEM.packBlock({ type: "PUBLIC KEY", bytes: x509.packSpki(jwk) });
+    } else if (-1 !== [ 'ssh', 'rfc4716' ].indexOf(format)) {
+      return SSH.packSsh(jwk);
+    } else {
+      throw new Error("Sanity Error: reached unreachable code block with format: " + format);
+    }
+  });
 };
 EC.pack = function (opts) {
   return Promise.resolve().then(function () {
diff --git a/lib/rsa.js b/lib/rsa.js
index 17ceccb..5d3ce26 100644
--- a/lib/rsa.js
+++ b/lib/rsa.js
@@ -5,6 +5,8 @@
 var RSA = exports.Rasha = {};
 var x509 = exports.x509;
 if ('undefined' !== typeof module) { module.exports = RSA; }
+var PEM = exports.PEM;
+var SSH = exports.SSH;
 var Enc = {};
 var textEncoder = new TextEncoder();
 
@@ -108,55 +110,57 @@ RSA.thumbprint = function (opts) {
 };
 
 RSA.export = function (opts) {
-  if (!opts || !opts.jwk || 'object' !== typeof opts.jwk) {
-    throw new Error("must pass { jwk: jwk }");
-  }
-  var jwk = JSON.parse(JSON.stringify(opts.jwk));
-  var format = opts.format;
-  var pub = opts.public;
-  if (pub || -1 !== [ 'spki', 'pkix', 'ssh', 'rfc4716' ].indexOf(format)) {
-    jwk = RSA.nueter(jwk);
-  }
-  if ('RSA' !== jwk.kty) {
-    throw new Error("options.jwk.kty must be 'RSA' for RSA keys");
-  }
-  if (!jwk.p) {
-    // TODO test for n and e
-    pub = true;
-    if (!format || 'pkcs1' === format) {
-      format = 'pkcs1';
-    } else if (-1 !== [ 'spki', 'pkix' ].indexOf(format)) {
-      format = 'spki';
-    } else if (-1 !== [ 'ssh', 'rfc4716' ].indexOf(format)) {
-      format = 'ssh';
+  return Promise.resolve().then(function () {
+    if (!opts || !opts.jwk || 'object' !== typeof opts.jwk) {
+      throw new Error("must pass { jwk: jwk }");
+    }
+    var jwk = JSON.parse(JSON.stringify(opts.jwk));
+    var format = opts.format;
+    var pub = opts.public;
+    if (pub || -1 !== [ 'spki', 'pkix', 'ssh', 'rfc4716' ].indexOf(format)) {
+      jwk = RSA.neuter({ jwk: jwk });
+    }
+    if ('RSA' !== jwk.kty) {
+      throw new Error("options.jwk.kty must be 'RSA' for RSA keys");
+    }
+    if (!jwk.p) {
+      // TODO test for n and e
+      pub = true;
+      if (!format || 'pkcs1' === format) {
+        format = 'pkcs1';
+      } else if (-1 !== [ 'spki', 'pkix' ].indexOf(format)) {
+        format = 'spki';
+      } else if (-1 !== [ 'ssh', 'rfc4716' ].indexOf(format)) {
+        format = 'ssh';
+      } else {
+        throw new Error("options.format must be 'spki', 'pkcs1', or 'ssh' for public RSA keys, not ("
+          + typeof format + ") " + format);
+      }
     } else {
-      throw new Error("options.format must be 'spki', 'pkcs1', or 'ssh' for public RSA keys, not ("
-        + typeof format + ") " + format);
+      // TODO test for all necessary keys (d, p, q ...)
+      if (!format || 'pkcs1' === format) {
+        format = 'pkcs1';
+      } else if ('pkcs8' !== format) {
+        throw new Error("options.format must be 'pkcs1' or 'pkcs8' for private RSA keys");
+      }
     }
-  } else {
-    // TODO test for all necessary keys (d, p, q ...)
-    if (!format || 'pkcs1' === format) {
-      format = 'pkcs1';
-    } else if ('pkcs8' !== format) {
-      throw new Error("options.format must be 'pkcs1' or 'pkcs8' for private RSA keys");
-    }
-  }
 
-  if ('pkcs1' === format) {
-    if (jwk.d) {
-      return PEM.packBlock({ type: "RSA PRIVATE KEY", bytes: x509.packPkcs1(jwk) });
+    if ('pkcs1' === format) {
+      if (jwk.d) {
+        return PEM.packBlock({ type: "RSA PRIVATE KEY", bytes: x509.packPkcs1(jwk) });
+      } else {
+        return PEM.packBlock({ type: "RSA PUBLIC KEY", bytes: x509.packPkcs1(jwk) });
+      }
+    } else if ('pkcs8' === format) {
+      return PEM.packBlock({ type: "PRIVATE KEY", bytes: x509.packPkcs8(jwk) });
+    } else if (-1 !== [ 'spki', 'pkix' ].indexOf(format)) {
+      return PEM.packBlock({ type: "PUBLIC KEY", bytes: x509.packSpki(jwk) });
+    } else if (-1 !== [ 'ssh', 'rfc4716' ].indexOf(format)) {
+      return SSH.pack({ jwk: jwk, comment: opts.comment });
     } else {
-      return PEM.packBlock({ type: "RSA PUBLIC KEY", bytes: x509.packPkcs1(jwk) });
+      throw new Error("Sanity Error: reached unreachable code block with format: " + format);
     }
-  } else if ('pkcs8' === format) {
-    return PEM.packBlock({ type: "PRIVATE KEY", bytes: x509.packPkcs8(jwk) });
-  } else if (-1 !== [ 'spki', 'pkix' ].indexOf(format)) {
-    return PEM.packBlock({ type: "PUBLIC KEY", bytes: x509.packSpki(jwk) });
-  } else if (-1 !== [ 'ssh', 'rfc4716' ].indexOf(format)) {
-    return SSH.pack({ jwk: jwk, comment: opts.comment });
-  } else {
-    throw new Error("Sanity Error: reached unreachable code block with format: " + format);
-  }
+  });
 };
 RSA.pack = function (opts) {
   // wrapped in a promise for API compatibility
diff --git a/lib/x509.js b/lib/x509.js
index f1ac559..901bb36 100644
--- a/lib/x509.js
+++ b/lib/x509.js
@@ -58,11 +58,11 @@
   x509.packPkcs1 = function (jwk) {
     var n = ASN1.UInt(Enc.base64ToHex(jwk.n));
     var e = ASN1.UInt(Enc.base64ToHex(jwk.e));
-  
+
     if (!jwk.d) {
       return Enc.hexToBuf(ASN1('30', n, e));
     }
-  
+
     return Enc.hexToBuf(ASN1('30'
     , ASN1.UInt('00')
     , n
@@ -159,10 +159,10 @@
   };
   /**
    * take a private jwk and creates a der from it
-   * @param {*} jwk 
+   * @param {*} jwk
    */
   x509.packPkcs8 = function (jwk) {
-    if (jwk.kty == 'RSA') {
+    if ('RSA' === jwk.kty) {
       if (!jwk.d) {
         // Public RSA
         return Enc.hexToBuf(ASN1('30'
@@ -219,6 +219,49 @@
     );
   };
   x509.packSpki = function (jwk) {
+    if (/EC/i.test(jwk.kty)) {
+      return x509.packSpkiEc(jwk);
+    }
+    return x509.packSpkiRsa(jwk);
+  };
+  x509.packSpkiRsa = function (jwk) {
+  if (!jwk.d) {
+    // Public RSA
+    return Enc.hexToBuf(ASN1('30'
+      , ASN1('30'
+        , ASN1('06', '2a864886f70d010101')
+        , ASN1('05')
+      )
+      , ASN1.BitStr(ASN1('30'
+        , ASN1.UInt(Enc.base64ToHex(jwk.n))
+        , ASN1.UInt(Enc.base64ToHex(jwk.e))
+      ))
+    ));
+  }
+
+  // Private RSA
+  return Enc.hexToBuf(ASN1('30'
+    , ASN1.UInt('00')
+    , ASN1('30'
+      , ASN1('06', '2a864886f70d010101')
+      , ASN1('05')
+    )
+    , ASN1('04'
+      , ASN1('30'
+        , ASN1.UInt('00')
+        , ASN1.UInt(Enc.base64ToHex(jwk.n))
+        , ASN1.UInt(Enc.base64ToHex(jwk.e))
+        , ASN1.UInt(Enc.base64ToHex(jwk.d))
+        , ASN1.UInt(Enc.base64ToHex(jwk.p))
+        , ASN1.UInt(Enc.base64ToHex(jwk.q))
+        , ASN1.UInt(Enc.base64ToHex(jwk.dp))
+        , ASN1.UInt(Enc.base64ToHex(jwk.dq))
+        , ASN1.UInt(Enc.base64ToHex(jwk.qi))
+      )
+    )
+  ));
+};
+  x509.packSpkiEc = function (jwk) {
     var x = Enc.base64ToHex(jwk.x);
     var y = Enc.base64ToHex(jwk.y);
     var objId = ('P-256' === jwk.crv) ? OBJ_ID_EC : OBJ_ID_EC_384;