diff --git a/lib/modules/Standards.pmod/PKCS.pmod/DSA.pmod b/lib/modules/Standards.pmod/PKCS.pmod/DSA.pmod
new file mode 100644
index 0000000000000000000000000000000000000000..e8fa45e6e7b873b7ae8dbca80111c5539f9293f7
--- /dev/null
+++ b/lib/modules/Standards.pmod/PKCS.pmod/DSA.pmod
@@ -0,0 +1,50 @@
+/* DSA.pmod
+ *
+ * DSA operations as defined in RFC-2459.
+ *
+ */
+
+/* NOTE: Unlike the functions in RSA.pmod, this function returns
+ * an object rather than a string. */
+
+import Standards.ASN1.Types;
+
+object algorithm_identifier(object|void dsa)
+{
+  return
+    dsa ? asn1_sequence( ({ .Identifiers.dsa_id,
+			    asn1_sequence( ({ asn1_integer(dsa->p),
+					      asn1_integer(dsa->q),
+					      asn1_integer(dsa->g) }) ) }) )
+    : asn1_sequence( ({ .Identifiers.dsa_id }) );
+}
+
+string public_key(object dsa)
+{
+  return asn1_integer(dsa->y)->get_der();
+}
+
+/* I don't know if this format interoperates with anything else */
+string private_key(object dsa)
+{
+  return asn1_sequence(Array.map(
+    ({ dsa->p, dsa->q, dsa->g, dsa->y, dsa->x }),
+    asn1_integer))->get_der();
+}
+
+object parse_private_key(string key)
+{
+    object a = Standards.ASN1.Decode.simple_der_decode(key);
+
+    if (!a
+	|| (a->type_name != "SEQUENCE")
+	|| (sizeof(a->elements) != 5)
+	|| (sizeof(a->elements->type_name - ({ "INTEGER" }))) )
+      return 0;
+
+    object dsa = Crypto.dsa();
+    dsa->set_public_key(@ a->elements[..3]->value);
+    dsa->set_private_key(a->elements[4]->value);
+
+    return dsa;
+}