From 72d149a8bda9ab560e9419a7f7046cf982081c33 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Henrik=20Grubbstr=C3=B6m=20=28Grubba=29?=
 <grubba@grubba.org>
Date: Sun, 23 Feb 2014 20:31:47 +0100
Subject: [PATCH] Standards.PKCS.CSR: Added CRI and sign_cri().

---
 lib/modules/Standards.pmod/PKCS.pmod/CSR.pmod | 101 +++++++++++++++++-
 .../Standards.pmod/PKCS.pmod/Certificate.pmod |  20 +++-
 2 files changed, 117 insertions(+), 4 deletions(-)

diff --git a/lib/modules/Standards.pmod/PKCS.pmod/CSR.pmod b/lib/modules/Standards.pmod/PKCS.pmod/CSR.pmod
index 6082aa3fc9..0d01690602 100644
--- a/lib/modules/Standards.pmod/PKCS.pmod/CSR.pmod
+++ b/lib/modules/Standards.pmod/PKCS.pmod/CSR.pmod
@@ -1,4 +1,4 @@
-//! Handling of Certificate Signing Requests (PKCS-10, RFC 2986)
+//! Handling of Certificate Signing Requests (PKCS-10, RFC 2314, RFC 2986)
 
 #pike __REAL_VERSION__
 // #pragma strict_types
@@ -17,6 +17,105 @@ class CRIAttributes
 // FIXME: Mark as deprecated!
 constant CSR_Attributes = CRIAttributes;
 
+//! CertificationRequestInfo
+//!
+//! This is the data that is signed by @[sign_cri()].
+class CRI
+{
+  inherit Sequence;
+
+  //!
+  void `version=(int v)
+  {
+    der = UNDEFINED;
+    if (v != 1) {
+      error("Only version 1 is supported.\n");
+    }
+    elements[0] = Integer(v-1);
+  }
+  int `version()
+  {
+    return elements[0]->value + 1;
+  }
+
+  //! Certificate subject.
+  void `subject=(Sequence i)
+  {
+    der = UNDEFINED;
+    elements[1] = i;
+  }
+  Sequence `subject()
+  {
+    return elements[1];
+  }
+
+  //! Public key information.
+  void `keyinfo=(Sequence ki)
+  {
+    der = UNDEFINED;
+    elements[2] = ki;
+  }
+  Sequence `keyinfo()
+  {
+    return elements[2];
+  }
+
+  //! Subject attributes.
+  void `attributes=(Set|CRIAttributes attrs)
+  {
+    der = UNDEFINED;
+    if ((attrs->type_name != "SET") &&
+	(attrs->type_name != "CONSTRUCTED")) {
+      error("Invalid attributes: %O.\n", attrs->type_name);
+    }
+    if ((attrs->get_cls() != 2) || attrs->get_tag() || attrs->raw) {
+      attrs = CRIAttributes(attrs->elements);
+    }
+    elements[3] = attrs;
+  }
+  CRIAttributes `attributes()
+  {
+    return elements[3];
+  }
+
+  protected void create(Sequence|void asn1)
+  {
+    if (asn1) {
+      if ((asn1->type_name != "SEQUENCE") ||
+	  (sizeof(asn1->elements) != 4) ||
+	  (asn1[0]->type_name != "INTEGER") ||
+	  asn1[0]->value) {
+	error("Invalid CRI.");
+      }
+      elements = asn1->elements;
+      attributes = elements[3];
+    } else {
+      elements = ({
+	Integer(0),		// version (v1)
+	Null,			// subject
+	Null,			// subjectPKInfo
+	CRIAttributes(({})),	// attributes
+      });
+    }
+  }
+}
+
+//! Sign a @[CRI] to generate a Certificate Signing Request.
+//!
+//! @param cri
+//!   CertificationRequestInfo to sign.
+//!
+//! @param sign
+//!   Signature to use. Must have a private key set that matches
+//!   the public key in the keyinfo in @[cri].
+//!
+//! @param hash
+//!   Hash algorithm to use for the signature.
+Sequence sign_cri(CRI cri, Crypto.Sign sign, Crypto.Hash hash)
+{
+  return Standards.PKCS.Signature.sign(cri, sign, hash);
+}
+
 //! Build a Certificate Signing Request.
 //!
 //! @param sign
diff --git a/lib/modules/Standards.pmod/PKCS.pmod/Certificate.pmod b/lib/modules/Standards.pmod/PKCS.pmod/Certificate.pmod
index d5fe16355d..4df7f0c5ca 100644
--- a/lib/modules/Standards.pmod/PKCS.pmod/Certificate.pmod
+++ b/lib/modules/Standards.pmod/PKCS.pmod/Certificate.pmod
@@ -315,24 +315,38 @@ class Attribute
 {
   inherit Sequence;
 
-  void create(mapping(string:object) types, string type,
-	      array(object) v)
+  protected void create(mapping(string:object) types, string type,
+			array(object) v)
   {
     if (!types[type])
       error( "Unknown attribute type '%s'\n", type);
     ::create( ({ types[type], Set(v) }) );
   }
+  protected variant void create(array(Object) elements)
+  {
+    if (sizeof(elements) != 2)
+      error("Invalid attribute encoding.\n");
+    ::create(elements);
+  }
 }
 
 class Attributes
 {
   inherit Set;
 
-  void create(mapping(string:object) types, mapping(string:array(object)) m)
+  protected void create(mapping(string:object) types,
+			mapping(string:array(object)) m)
   {
     ::create(map(indices(m),
 		 lambda(string field, mapping m, mapping t) {
 		   return Attribute(t, field, m[field]);
 		 }, m, types));
   }
+  protected variant void create(array(Object) elements)
+  {
+    ::create(map(elements,
+		 lambda(object e) {
+		   return Attribute(e->elements);
+		 }));
+  }
 }
-- 
GitLab