labs-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From dr...@apache.org
Subject svn commit: r606690 - in /labs/badca: ./ BaDCA/ openssl/ tests/ tests/ca/test01/ tests/logs/
Date Mon, 24 Dec 2007 10:52:35 GMT
Author: dreid
Date: Mon Dec 24 02:52:33 2007
New Revision: 606690

URL: http://svn.apache.org/viewvc?rev=606690&view=rev
Log:
Add the start of logging code
Add test for logging
Add ability to create certs from the CA, either self signed or
from a CSR
Rework certificate code to make it less repetitive
Correct some minor errors in the rsa code
Add code to the test runner to cleanup prior to running
Add code to compare keys using the modulus


Added:
    labs/badca/BaDCA/Logging.py
    labs/badca/tests/05LoggingTestCase.py
    labs/badca/tests/logs/   (with props)
Modified:
    labs/badca/   (props changed)
    labs/badca/BaDCA/Certificates.py
    labs/badca/BaDCA/Keys.py
    labs/badca/BaDCA/baseCA.py
    labs/badca/Makefile.in
    labs/badca/openssl/certmodule.c
    labs/badca/openssl/rsamodule.c
    labs/badca/tests/01KeysTestCase.py
    labs/badca/tests/04baseCATestCase.py
    labs/badca/tests/ca/test01/   (props changed)
    labs/badca/tests/runTests.py

Propchange: labs/badca/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Mon Dec 24 02:52:33 2007
@@ -3,4 +3,5 @@
 config.*
 *.cache
 *.pem
+*.log
 

Modified: labs/badca/BaDCA/Certificates.py
URL: http://svn.apache.org/viewvc/labs/badca/BaDCA/Certificates.py?rev=606690&r1=606689&r2=606690&view=diff
==============================================================================
--- labs/badca/BaDCA/Certificates.py (original)
+++ labs/badca/BaDCA/Certificates.py Mon Dec 24 02:52:33 2007
@@ -1,4 +1,6 @@
 import os, sys
+from time import strptime
+from datetime import datetime
 
 from BaDCA.Utils import getSHA1
 
@@ -9,10 +11,15 @@
 class Certificate:
     filename = None
     cert = None
+    serial = None
     key = None
     keyPaths = []
-    
-    def __init__(self, filename = None, obj = None):
+    notBefore = None
+    notAfter = None
+
+    def __init__(self, filename = None, obj = None, keyPaths = None):
+        if keyPaths is not None:
+            self.addKeyPaths(keyPaths)
         if filename is not None:
             self.readFromFile(filename)
         if obj is not None:
@@ -28,11 +35,27 @@
             return 1
         return 0
 
+    # Match serials
+    # TODO - should we also match the modulus?
+    def __eq__(self, x):
+        if self.getSerial() == x.getSerial():
+            return 1
+        return 0
+
+    def getSerial(self):
+        if self.serial is None:
+            self.serial = cert.getSerial(self.cert)
+        return self.serial
+
     def getKey(self):
         if self.cert is None or self.key is None:
             return None
         return self.key
 
+    def addKeyPaths(self, paths):
+        for p in paths:
+            self.addKeyPath(p)
+
     # should we store the path in the certificate object?
     def addKeyPath(self, path):
         if not path in self.keyPaths:
@@ -76,10 +99,39 @@
         except:
             return None
 
+    def asTime(self, which):
+        try:
+            dt = self.info[which]
+            try:
+                return datetime.strptime(dt, "%b %d %H:%M:%S %Y %Z")
+            except ValueError:
+                return None        
+        except KeyError:
+            return None
+
+    # Compare against supplied time (which should be in UTC)
+    def checkUTC(self, dt):
+        if self.notBefore is None or self.notAfter is None:
+            return False
+        if self.notBefore <= dt and self.notAfter >= dt:
+            return True
+        return False
+
+    # Compare against UTC now
+    def checkNow(self):
+        dt = datetime.utcnow()
+        if self.notBefore is None or self.notAfter is None:
+            return False
+        if self.notBefore <= dt and self.notAfter >= dt:
+            return True
+        return False
+
     def processCertificate(self):
         if self.cert is None:
             return
         self.info = cert.parse(self.cert)
+        self.notBefore = self.asTime("notBefore")
+        self.notAfter = self.asTime("notAfter")
         key = Keys.RSAKey(searchPath = self.keyPaths, \
                           certificate = self.cert)
         if key.isValid():
@@ -98,10 +150,38 @@
             return thecert
         return None
 
+    def createSelfSignedFromDict(self, subject, key = None, \
+                                 options = None):
+        if key is None:
+            if self.key is None:
+                return None
+            thekey = self.key
+        else:
+            thekey = key
+        if not thekey.hasPrivate():
+            return None
+        self.cert = cert.createCertificateFromDict(subject, \
+                                                thekey.privRSA, options)
+        if self.cert is not None:
+            self.key = thekey
+            self.processCertificate()
+
     def writeToFile(self, filename = None):
         if self.cert is None:
             return 0
         if filename is None:
-            filename = cert.getSerial(self.cert) + '.pem'
-        return cert.write(self.cert, filename)
+            filename = self.getSerial() + '.pem'
+        rv = cert.write(self.cert, filename)
+        if rv == 1 and self.filename is not None:
+            self.filename = filename
+        return rv
+
+    def writeToDirectory(self, dirname):
+        if self.cert is None:
+            return 0
+        if not os.path.isdir(dirname):
+            return 0
+        self.filename = os.path.abspath( \
+                       os.path.join(dirname, self.getSerial() + '.pem'))
+        return cert.write(self.cert, self.filename)
 

Modified: labs/badca/BaDCA/Keys.py
URL: http://svn.apache.org/viewvc/labs/badca/BaDCA/Keys.py?rev=606690&r1=606689&r2=606690&view=diff
==============================================================================
--- labs/badca/BaDCA/Keys.py (original)
+++ labs/badca/BaDCA/Keys.py Mon Dec 24 02:52:33 2007
@@ -40,7 +40,8 @@
     # Apply to all keys
     bits = 0
     sha1 = ''
-    
+    modulus = None
+
     avail = KEY_NONE
     directories = []
 
@@ -55,14 +56,17 @@
             self.fromCertificate(certificate)
         if csr is not None:
             self.fromCSR(csr)
-
-        # If we have been given either the public or private key object
-        # save them here
-#        if public is not None:
-#            self.pubRSA = public
-#        if private is not None:
-#            self.privRSA = private
-#        self.processKeys()
+        if filename is not None:
+            try:
+                self.readPrivateKey(filename)
+            except IOError:
+                self.readPublicKey(filename)
+
+    # should we also compare key types, ie private with private?
+    def __eq__(self, x):
+        if self.modulus == x.modulus:
+            return 1
+        return 0
 
     def getPrivateKey(self):
         return self.privRSA
@@ -70,9 +74,6 @@
     def getPublicKey(self):
         return self.pubRSA
 
-    def setDirectory(self, thedir):
-        self.directory = thedir
-
     def addSearchDirectories(self, dirlist):
         for d in dirlist:
             self.addSearchDirectory(d)
@@ -129,22 +130,25 @@
             return rsa.getPublicKeyString(self.pubRSA)
         return None       
 
-    def writeToDirectory(self, dir = None):
+    def writeToDirectory(self, dir = None, \
+                                    which = (KEY_PRIVATE | KEY_PUBLIC)):
         if dir is None:
             baseDir = '.'
         else:
             baseDir = dir
 
-        if self.privRSA is not None:
-            fn = os.path.join(baseDir, self.sha1 + '.key')
-            if rsa.writePrivate(self.privRSA, fn) != 1:
-                return 0
-            self.privFn = fn
-        if self.pubRSA is not None:
-            fn = os.path.join(baseDir, self.sha1 + '.public.key')
-            if rsa.writePublic(self.pubRSA, fn) != 1:
-                return 0
-            self.pubFn = fn
+        if (which & KEY_PRIVATE):
+            if self.privRSA is not None:
+                fn = os.path.join(baseDir, self.sha1 + '.key')
+                if rsa.writePrivate(self.privRSA, fn) != 1:
+                    return 0
+                self.privFn = fn
+        if (which & KEY_PUBLIC):
+            if self.pubRSA is not None:
+                fn = os.path.join(baseDir, self.sha1 + '.public.key')
+                if rsa.writePublic(self.pubRSA, fn) != 1:
+                    return 0
+                self.pubFn = fn
         return 1
 
     def processKeys(self):
@@ -163,12 +167,14 @@
                     self.avail = KEY_PRIVATE | KEY_PUBLIC
             else:
                 self.avail = KEY_PRIVATE
+            self.modulus = rsa.getModulus(self.privRSA)
         elif self.pubRSA is not None:
             pubKey = rsa.getPublicKeyString(self.pubRSA)
             self.bits = rsa.getKeyStrength(self.pubRSA)
             self.sha1 = getSHA1(pubKey)
             self.avail = KEY_PUBLIC
             self.searchPrivateKey()
+            self.modulus = rsa.getModulus(self.pubRSA)
 
     def readPublicKeyFromMemory(self, string):
         self.pubRSA = rsa.fromMemoryPublic(string)
@@ -186,7 +192,7 @@
             self.Reset()
             self.addSearchDirectory(os.path.dirname(filename))
         self.privRSA = rsa.read(filename)
-        if self.privRSA:
+        if self.privRSA is not None:
             self.privFn = filename
             self.avail |= KEY_PRIVATE
 
@@ -236,6 +242,7 @@
             print "  Public key  : NOT AVAILABLE"
 
         print "\n"
+        print "  Modulus: %s" % self.modulus
 
     def Reset(self):
         self.pubRSA = None

Added: labs/badca/BaDCA/Logging.py
URL: http://svn.apache.org/viewvc/labs/badca/BaDCA/Logging.py?rev=606690&view=auto
==============================================================================
--- labs/badca/BaDCA/Logging.py (added)
+++ labs/badca/BaDCA/Logging.py Mon Dec 24 02:52:33 2007
@@ -0,0 +1,72 @@
+import os
+from datetime import datetime
+
+class Log:
+    directory = None
+    name = None
+    filename = None
+    fH = None
+
+    def __init__(self, name = None, directory = None):
+        if name is not None:
+            self.name = name
+        if self.name is None:
+            self.name = 'badca'
+        if directory is not None:
+            if self.setDirectory(directory) != 1:
+                return None
+
+    def setDirectory(self, directory):
+        if not os.path.isdir(directory):
+            return 0
+        self.directory = directory
+        return self.makeFilename()
+
+    def makeFilename(self):
+        base = os.path.abspath(os.path.join(self.directory, self.name))
+        if os.path.isdir(base):
+            return 0
+        self.filename = base + '.log'
+        return 1
+
+    def isValid(self):
+        if self.name is not None and self.filename is not None:
+            return True
+        return False
+
+    def openLog(self):
+        if self.filename is None:
+            return 0
+        f = open(self.filename, 'a')
+        if f is None:
+            return 0
+        self.fH = f
+        self.Log("Log opened")
+        return 1
+
+    def closeLog(self):
+        if self.fH is None:
+            return 0
+        self.Log("Log closed")
+        self.fH.close()
+        self.fH = None
+        return 1
+
+    def Log(self, msg, *aList):
+        if self.fH is None:
+            if self.openLog() != 1:
+                return
+        tm = datetime.utcnow()
+        # todo - use a better format for the date/time...
+        if aList is None:
+            theStr = "%s: %s" % (str(tm), msg)
+        else:
+            theMsgStr = msg % (aList)
+            theStr = "%s: %s" % (str(tm), theMsgStr)
+        if not theStr.endswith("\n"):
+            self.fH.write(theStr + "\n")
+        else:
+            self.fH.write(theStr)
+        self.fH.flush()
+
+

Modified: labs/badca/BaDCA/baseCA.py
URL: http://svn.apache.org/viewvc/labs/badca/BaDCA/baseCA.py?rev=606690&r1=606689&r2=606690&view=diff
==============================================================================
--- labs/badca/BaDCA/baseCA.py (original)
+++ labs/badca/BaDCA/baseCA.py Mon Dec 24 02:52:33 2007
@@ -1,7 +1,9 @@
-import os, sys
+import os, re, sys
 from stat import *
 
 from BaDCA.Utils import getSHA1
+from BaDCA import Keys, CSRs, Certificates
+from BaDCA.Keys import KEY_PRIVATE
 
 def extractConfig(s, n, default = None):
     try:
@@ -25,16 +27,23 @@
     settings = {}
     options = {}
     subject = {}
+    paths = {}
     minStrength = 0
     rootValidity = 0
     issuedValidity = 0
     configOK = 0
+    currentCertificate = None
+    currentKey = None
 
     def __init__(self, baseDir = None):
+        if self.baseDir is not None:
+            self.Reset()
         if baseDir is not None:
             if os.path.isdir(baseDir):
                 self.baseDir = os.path.abspath(baseDir)
                 self.configOK = self.getConfig()
+                self.readKeys()
+                self.readCerts()
 
     def getConfig(self):
         configFn = os.path.join(self.baseDir, 'conf.py')
@@ -58,8 +67,8 @@
         self.options['ignore'] = extractConfig(settings, 'ignore')
         self.options['attributes'] = extractConfig(settings, 'attributes')
 
-        print str(self.options)
-        print str(self.subject)
+#        print str(self.options)
+#        print str(self.subject)
 
         return self.checkDirectories() 
 
@@ -88,7 +97,52 @@
                 except:
                     print "Unable to create '%s'" % ckdir
                     return 0
-                print "Created directory '%s'" % ckdir
+        # Now we have the directories created, set some path variables
+        # as a shortcut to using them.
+        dirVars = {
+                'private': 'private',
+                'CACerts': 'certs/ca',
+                'IssuedCerts': 'certs/issued',
+                'keys': 'private/keys'
+                  }
+        for d in dirVars.keys():
+            self.paths[d] = os.path.abspath(os.path.join( \
+                                              self.baseDir, dirVars[d]))
+
+        return 1
+
+    def readKeys(self):
+        fileMatcher = re.compile("^\S*\.key$")
+        if not os.path.isdir(self.paths['keys']):
+            return 0
+        files = os.listdir(self.paths['keys'])
+        for f in files:
+            if fileMatcher.match(f):
+                fn = os.path.abspath(os.path.join(self.paths['keys'], f))
+                aKey = Keys.RSAKey(filename = fn)
+                if aKey is not None and aKey.hasPrivate():
+                    self.keys.append(aKey)
+        return 1
+
+    def readCerts(self):
+        fileMatcher = re.compile("^\S*\.pem$")
+        keyPaths = [ self.paths['keys'] ]
+        if not os.path.isdir(self.paths['CACerts']):
+            return 0
+        files = os.listdir(self.paths['CACerts'])
+        for f in files:
+            if fileMatcher.match(f):
+                fn = os.path.abspath(os.path.join(self.paths['CACerts'], f))
+                aCert = Certificates.Certificate(filename = fn, \
+                                        keyPaths = keyPaths)
+                if aCert is not None:
+                    for c in self.certs:
+                        if c == aCert:
+                            aCert = None
+                    if aCert is not None:
+                        self.certs.append(aCert)
+
+        self.setCurrentCertAndKey()
         return 1
 
     def isValid(self):
@@ -98,4 +152,60 @@
            self.rootValidity == 0:
             return False
         return True
+
+    def hasCertificate(self):
+        if self.currentCertificate is None:
+            return False
+        return True
+
+    def setCurrentCertAndKey(self):
+        self.currentCertificate = None
+        self.currentKey = None
+        for c in self.certs:
+            if c.checkNow():
+                if self.currentCertificate is None:
+                    self.currentCertificate = c
+                    break
+        # todo - set the current key!
+        return 1
+        
+    def createSelfSigned(self):
+        key = Keys.RSAKey()
+        if key is None:
+            return 0
+        if key.create(2048) != 1:
+            return 0
+
+        cert = Certificates.Certificate()
+        cert.createSelfSignedFromDict(self.subject, key, self.options)
+        if cert is None:
+            return 0
+
+        if key.writeToDirectory(self.paths['keys'], which = KEY_PRIVATE) != 1 or \
+           cert.writeToDirectory(self.paths['CACerts']) != 1:
+            return 0
+
+        self.keys.append(key)
+        self.certs.append(cert)
+
+        self.setCurrentCertAndKey()
+
+        return 1
+
+    def signRequest(self, request):
+        if not self.hasCertificate():
+            return 0
+        nCert = self.currentCertificate.signRequest(request, self.options)
+        if nCert is None:
+            return 0
+        nCert.writeToDirectory(self.paths['IssuedCerts'])
+        return 1
+
+    def Reset(self):
+        self.currentCertificate = None
+        self.currentKey = None
+        self.certs[:] = []
+        self.keys[:] = []
+        self.settings = {}
+        self.options = {}
 

Modified: labs/badca/Makefile.in
URL: http://svn.apache.org/viewvc/labs/badca/Makefile.in?rev=606690&r1=606689&r2=606690&view=diff
==============================================================================
--- labs/badca/Makefile.in (original)
+++ labs/badca/Makefile.in Mon Dec 24 02:52:33 2007
@@ -42,3 +42,9 @@
 	gdb --args @PYTHON@ @top_srcdir@/tests/runTests.py \
 	           @top_srcdir@/tests Cert
 
+debugca:
+	@echo "Type 'r' to start debugging..."
+	PYTHONPATH=".:@EXT_PATH@:$$PYTHONPATH" \
+	gdb --args @PYTHON@ @top_srcdir@/tests/runTests.py \
+	           @top_srcdir@/tests baseCA
+

Modified: labs/badca/openssl/certmodule.c
URL: http://svn.apache.org/viewvc/labs/badca/openssl/certmodule.c?rev=606690&r1=606689&r2=606690&view=diff
==============================================================================
--- labs/badca/openssl/certmodule.c (original)
+++ labs/badca/openssl/certmodule.c Mon Dec 24 02:52:33 2007
@@ -284,6 +284,31 @@
     return 1;
 }
 
+static X509_NAME *
+makeSubjectFromDict(PyObject *dict, unsigned long chtype)
+{
+    X509_NAME *subj = X509_NAME_new();
+    int nid;
+    PyObject *pKey = NULL, *pValue = NULL;
+    int pos = 0;
+    
+    while (PyDict_Next(dict, &pos, &pKey, &pValue)) {
+        char *key = PyString_AsString(pKey);
+        char *val = PyString_AsString(pValue);
+
+        if ((nid = OBJ_txt2nid(key)) == NID_undef &&
+            (nid = OBJ_sn2nid(key)) == NID_undef) {
+            printf("Failed to find key %s\n", key);
+            continue;
+        }
+
+        X509_NAME_add_entry_by_NID(subj, nid, chtype, 
+                                   (unsigned char *)val,
+                                   -1, -1, 0);
+    }
+    return subj;
+}
+
 static int
 addV3Attributes(X509 *cert, X509 *issuer, PyObject *attrDict)
 {
@@ -291,7 +316,7 @@
     int pos = 0;
     PyObject *pKey = NULL, *pValue = NULL;
 
-    X509V3_set_ctx(&ctx, issuer, cert, NULL, NULL, 0);
+    X509V3_set_ctx(&ctx, issuer ? issuer : cert, cert, NULL, NULL, 0);
     
     while (PyDict_Next(attrDict, &pos, &pKey, &pValue)) {
         char *key = PyString_AsString(pKey);
@@ -324,21 +349,102 @@
      * create the certificate, or we get some very "odd" results.
      * Not cool!
      */
-    if (X509_check_private_key(cert, pkey) == 1) {
+//    if (X509_check_private_key(cert, pkey) == 1) {
         if (X509_sign(cert, pkey, digest))
             rv = 1;
         else
             PyErr_SetString(PyExc_RuntimeError, "Error signing the "
                                       "certificate using supplied key");
-    } else
-        PyErr_SetString(PyExc_RuntimeError, "Private key supplied is NOT "
-                       "the key used to create the certificate!");
+//    } else
+//        PyErr_SetString(PyExc_RuntimeError, "Private key supplied is NOT "
+//                       "the key used to create the certificate!");
 
     EVP_PKEY_free(pkey);
     return rv;
 }
 
+static X509* createCertificate(X509_NAME *subject, X509_NAME *issuer,
+                               EVP_PKEY *pubKey, RSA *privKey, 
+                               long startOffset, long period,
+                               PyObject *attributes, X509 *caCert)
+
+{
+    X509 *cert = NULL;
 
+//    if (caCert && X509_check_private_key(caCert, pkey) != 1) {
+//        PyErr_SetString(PyExc_RuntimeError, "Private key supplied is NOT "
+//                       "the key used to create the certificate!");
+//        return NULL;
+//    }
+
+    cert = X509_new();
+    if (!cert) {
+        PyErr_SetString(PyExc_MemoryError, "Unable to get a new X509 "
+                                           "certificate structure");
+        return NULL;
+    }
+    /* We're creating a Version 3 certificate, so set that before we do
+     * anything else.
+     */
+    if (X509_set_version(cert, 2L) != 1) {
+        PyErr_SetString(PyExc_RuntimeError, "Unable to set the version "
+                                            "of the new certificate");
+        goto out;
+    }
+    /* Set the subject of the new certificate */
+    if (X509_set_subject_name(cert, subject) != 1) {
+        PyErr_SetString(PyExc_RuntimeError, "Unable to set the subject "
+                                      "name of the new certificate");
+        goto out;
+    }
+    /* Set the issuer subject line */
+    if (X509_set_issuer_name(cert, issuer) != 1) {
+        PyErr_SetString(PyExc_RuntimeError, "Unable to set the issuer "
+                                     "name of the new certificate");
+        goto out;
+    }
+    /* Add the public key we'll be using */
+    if (X509_set_pubkey(cert, pubKey) != 1) {
+        PyErr_SetString(PyExc_RuntimeError, "Unable to set the public "
+                                      "key of the new certificate");
+        goto out;
+    }
+    /* Set the initial date/times */
+    if (!(X509_gmtime_adj(X509_get_notBefore(cert), startOffset))) {
+        PyErr_SetString(PyExc_RuntimeError, "Unable to set notBefore time");
+        goto out;
+    }
+    /* Set the validity period of the certificate by setting it's
+     * expiration date.
+     */
+    if (!(X509_gmtime_adj(X509_get_notAfter(cert), startOffset + period))) {
+        PyErr_SetString(PyExc_RuntimeError, "Unable to set notAfter time");
+        goto out;
+    }
+    /* Set the serial number of the certificate. */
+    if (certificate_set_serial(cert) == 0)
+        goto out;
+    /* Add the X509_v3 extensions we need to set. If this fails
+     * the exeception will already have been set, so just bail out.
+     */
+    if (attributes && addV3Attributes(cert, caCert, attributes) != 1)
+        goto out;
+
+    /* Claim credit for the creation... 
+     * We don't care if this fails ;-)
+     */
+    certificateAddExtension(cert, NULL, "nsComment", "Created by BaDCA");
+
+    /* Finally, sign the certificate with the private key of the issuing
+     * certificate. Once this is done, the certificate is complete.
+     */
+    if (signCertificateWithKey(cert, privKey) ==1)
+        return cert;
+
+out:
+    X509_free(cert);
+    return NULL;
+}
 
 /***********************************************************************
  **
@@ -575,14 +681,13 @@
 {
     X509 *cert = NULL, *issuer = NULL;
     X509_REQ *req = NULL;
-    X509V3_CTX ctx;
     X509_NAME *xn_req = NULL, *subject = NULL;
+    X509_NAME *issuerSubject = NULL;
     RSA *key = NULL;
     EVP_PKEY *pkey = NULL;
     PyObject *optionsDict = NULL, *attrDict = NULL;
     PyObject *removeList = NULL, *ignoreList = NULL;
     void *tmp[3];
-    int rv;
 
     if (! PyArg_ParseTuple(args, "OOO|O", &tmp[0], &tmp[1], &tmp[2], 
                            &optionsDict))
@@ -603,45 +708,18 @@
         ignoreList = PyDict_GetItem(optionsDict, Py_BuildValue("s", "ignore"));
     }
 
-    cert = X509_new();
-    if (!cert) {
-        PyErr_SetString(PyExc_MemoryError, "Unable to get a new X509 "
-                                           "certificate structure");
-        return NULL;
-    }
-
-    /* Make it a V3 certificate. */
-    if (X509_set_version(cert, 2L) != 1) {
-        PyErr_SetString(PyExc_RuntimeError, "Unable to set the version "
-                                            "of the new certificate");
+    issuerSubject = X509_get_subject_name(issuer);
+    if (! issuerSubject) {
+        PyErr_SetString(PyExc_RuntimeError, "Unable to get the "
+                                    "subject name from the issuer");
         goto out;
     }
 
-    {
-        X509_NAME *issuerSubject = X509_get_subject_name(issuer);
-
-        if (! issuerSubject) {
-            PyErr_SetString(PyExc_RuntimeError, "Unable to get the "
-                                        "subject name from the issuer");
-            goto out;
-        }
-
-        /* Set the issuing certificate subject as the issuer subject for
-         * the new certificate.
-         */
-        if (X509_set_issuer_name(cert, issuerSubject) != 1) {
-            PyErr_SetString(PyExc_RuntimeError, "Unable to set the issuer "
-                                         "name of the new certificate");
-            goto out;
-        }
-
-        subject = X509_NAME_dup(issuerSubject);       
-
-        if (! subject) {
-            PyErr_SetString(PyExc_RuntimeError, "Unable to duplicate the "
-                                        "subject name from the issuer");
-            goto out;
-        }
+    subject = X509_NAME_dup(issuerSubject);       
+    if (! subject) {
+        PyErr_SetString(PyExc_RuntimeError, "Unable to duplicate the "
+                                    "subject name from the issuer");
+        goto out;
     }
 
     /* We create the subject for the new certificate by copying the
@@ -666,14 +744,6 @@
      */
     if (mergeSubjects(subject, xn_req, ignoreList) != 1)
         goto out;
-    /* Now set the final subject into the certificate! */
-    if (X509_set_subject_name(cert, subject) != 1) {
-        PyErr_SetString(PyExc_RuntimeError, "Unable to set the subject "
-                                      "name of the new certificate");
-        goto out;
-    }
-    X509_NAME_free(subject);
-    subject = NULL;
 
     /* The public key associated with the generated certificate is the
      * one that was used to create the signing request. Extract the 
@@ -685,57 +755,68 @@
                 "from the supplied request");
         goto out;
     }
-    rv = X509_set_pubkey(cert, pkey);
-    EVP_PKEY_free(pkey);
-    pkey = NULL;
-    if (rv != 1) {
-        PyErr_SetString(PyExc_RuntimeError, "Unable to set the public "
-                                      "key of the new certificate");
-        goto out;
-    }
-	
-    /* Set the initial date/times */
-    if (!(X509_gmtime_adj(X509_get_notBefore(cert), 0))) {
-        PyErr_SetString(PyExc_RuntimeError, "Unable to set notBefore time");
-        goto out;
-    }
-    if (!(X509_gmtime_adj(X509_get_notAfter(cert), 36400))) {
-        PyErr_SetString(PyExc_RuntimeError, "Unable to set notAfter time");
-        goto out;
-    }
 
-    /* Set the serial number of the certificate. */
-    if (certificate_set_serial(cert) == 0)
-        goto out;
+    cert = createCertificate(subject, issuerSubject, pkey, key,
+                             0, 36400, attrDict, issuer);
 
-    /* Add the X509_v3 extensions we need to set. If this fails
-     * the exeception will already have been set, so just bail out.
-     */
-    if (attrDict && addV3Attributes(cert, issuer, attrDict) != 1)
-        goto out;
+out:
+    /* Free the structures we need to. */
+    if (pkey)
+        EVP_PKEY_free(pkey);
+    if (subject)
+        X509_NAME_free(subject);
 
-    /* Claim credit for the creation... 
-     * We don't care if this fails ;-)
+    /* If we have a certificate, return it. Otherwise return NULL as the
+     * error will have been set by the function that caused it :-)
      */
-    certificateAddExtension(cert, &ctx, "nsComment", "Created by BaDCA");
+    if (cert)
+        return PyCObject_FromVoidPtr(cert, delcert);
+    return NULL;
+}
 
-    /* Finally, sign the certificate with the private key of the issuing
-     * certificate. Once this is done, the certificate is complete.
-     */
-    if (signCertificateWithKey(cert, key) == 0)
-        goto out;
+static PyObject *
+createSelfSignedCertificate(PyObject *self, PyObject *args)
+{
+    PyObject *subjectDict = NULL;
+    PyObject *optionsDict = NULL, *attrDict = NULL;
+    void *tmp = NULL;
+    X509_NAME *subject = NULL;
+    RSA *key = NULL;
+    X509 *cert = NULL;
+    EVP_PKEY *pkey = NULL;
+    unsigned long chtype = MBSTRING_ASC;
 
-    /* All is well, we have a new certificate, so return it! */
-    return PyCObject_FromVoidPtr(cert, delcert);
+    if (! PyArg_ParseTuple(args, "OO|O", &subjectDict, &tmp, 
+                           &optionsDict))
+        return NULL;
+
+    key = (RSA *)PyCObject_AsVoidPtr(tmp);
+    if (!key || !subjectDict)
+        return NULL;
+
+    if (optionsDict)
+        attrDict = PyDict_GetItem(optionsDict, Py_BuildValue("s", "attributes"));
+
+    pkey = EVP_PKEY_new();
+    if (!pkey) {
+        PyErr_SetString(PyExc_RuntimeError, "Unable to create PKEY object");
+        return NULL;
+    }
+    EVP_PKEY_assign_RSA(pkey, key);
+
+    subject = makeSubjectFromDict(subjectDict, chtype);
+    if (!subject) {
+        PyErr_SetString(PyExc_RuntimeError, "Unable to create subject");
+        return NULL;
+    }
+
+    cert = createCertificate(subject, subject, pkey, key,
+                             0, 36400, attrDict, NULL);
+
+    X509_NAME_free(subject);
 
-    /* below this is used for error cases */
-out:
-    if (subject)
-        X509_NAME_free(subject);
-    if (pkey)
-        EVP_PKEY_free(pkey);
     if (cert)
-        X509_free(cert);
+        return PyCObject_FromVoidPtr(cert, delcert);
     return NULL;
 }
 
@@ -764,6 +845,8 @@
     { "parse", parseCertificate, METH_VARARGS, "Parse a certificate" },
     { "signRequest", signRequestWithCertificate, METH_VARARGS,
          "Create a certificate from a CSR using a root certificate" },
+    { "createCertificateFromDict", createSelfSignedCertificate, METH_VARARGS,
+         "Create a self signed 'root' certificate using a dict for the subject" },
     { "getSerial", getCertificateSerial, METH_VARARGS, "Get the serial from a certificate"
},
     { NULL, NULL, 0, NULL },
 };

Modified: labs/badca/openssl/rsamodule.c
URL: http://svn.apache.org/viewvc/labs/badca/openssl/rsamodule.c?rev=606690&r1=606689&r2=606690&view=diff
==============================================================================
--- labs/badca/openssl/rsamodule.c (original)
+++ labs/badca/openssl/rsamodule.c Mon Dec 24 02:52:33 2007
@@ -225,6 +225,7 @@
     if (BN_set_word(bn, f4) &&
         RSA_generate_key_ex(rsa, numBits, bn, &cb)) {
         /* return a pointer to the RSA structure */
+        RSA_up_ref(rsa);
         return PyCObject_FromVoidPtr(rsa, delrsa);
     }
     Py_INCREF(Py_None);
@@ -463,6 +464,33 @@
     return Py_BuildValue("l", BN_num_bits(rsa->n));
 }
 
+static PyObject *
+getModulus(PyObject *self, PyObject *args)
+{
+    RSA *rsa = NULL;
+    PyObject *temp = NULL, *rv = NULL;
+    BIO *out = NULL;
+
+    if (! PyArg_ParseTuple(args, "O", &temp))
+        return NULL;
+
+    if ((rsa = getRSAFromPython(temp)) == NULL)
+        return NULL;
+
+    out = BIO_new(BIO_s_mem());
+    if (out) {
+        char *ptr = NULL;
+        long sz = 0;
+    
+        BN_print(out,rsa->n);
+        (void)BIO_flush(out);
+        sz = BIO_get_mem_data(out, &ptr);
+        rv = PyString_FromStringAndSize(ptr, sz);
+        BIO_free(out);        
+    }
+    return rv;
+}
+
 static PyMethodDef RSAMethods[] = {
     { "genrsa", genrsa, METH_VARARGS, "Generate an RSA Key" },
     { "fromX509", fromX509, METH_VARARGS, "Get an RSA key from an X509 certificate" },
@@ -475,6 +503,7 @@
     { "getPublicKey", getRSAPublic, METH_VARARGS, "Get public key as an object" },
     { "getPublicKeyString", getRSAPublicString, METH_VARARGS, "Get public key as a string"
},
     { "getKeyStrength", getBits, METH_VARARGS, "Get the key strength (in bits)" },
+    { "getModulus", getModulus, METH_VARARGS, "Get the key modulus" },
     { NULL, NULL, 0, NULL },
 };
 

Modified: labs/badca/tests/01KeysTestCase.py
URL: http://svn.apache.org/viewvc/labs/badca/tests/01KeysTestCase.py?rev=606690&r1=606689&r2=606690&view=diff
==============================================================================
--- labs/badca/tests/01KeysTestCase.py (original)
+++ labs/badca/tests/01KeysTestCase.py Mon Dec 24 02:52:33 2007
@@ -82,5 +82,12 @@
                                       "Failed to create key from memory"
         assert self.obj.hasPublic(), "Error creating key"
 
+    def test10(self):
+        """ Test key equality checks """
+        k1 = Keys.RSAKey(filename = 'tests/keys/test1.public.key')
+        k2 = Keys.RSAKey(filename = 'tests/keys/test2.public.key')
+        assert k1 != k2, "The keys should NOT be equal"
+        assert k1 == k1, "Same key should equal itself"
+
 if __name__ == "__main__":
     unittest.main()

Modified: labs/badca/tests/04baseCATestCase.py
URL: http://svn.apache.org/viewvc/labs/badca/tests/04baseCATestCase.py?rev=606690&r1=606689&r2=606690&view=diff
==============================================================================
--- labs/badca/tests/04baseCATestCase.py (original)
+++ labs/badca/tests/04baseCATestCase.py Mon Dec 24 02:52:33 2007
@@ -1,6 +1,6 @@
 import unittest
 
-from BaDCA import baseCA
+from BaDCA import CSRs, baseCA
 from BaDCA.Testing import *
 
 class BaDCAbaseCATestCase(unittest.TestCase):
@@ -17,6 +17,32 @@
         assert ca is not None, "Failed to create a baseCA object"
         assert ca.isValid(), "baseCA isn't valid!"
 
+    def test03(self):
+        """ Testing creation of CA self signed certificate"""
+        ca = baseCA.baseCA(baseDir='tests/ca/test01')
+        assert ca is not None, "Failed to create a baseCA object"
+        assert ca.isValid(), "baseCA isn't valid!"
+        assert ca.createSelfSigned() == 1, "Unable to create self signed certiifcate"
+        assert ca.hasCertificate(), "No certificate created!"
+        ca.Reset()
+
+    def test04(self):
+        """ Testing creation of a valid CA """
+        # This should now have a self signed certificate available!
+        ca = baseCA.baseCA(baseDir='tests/ca/test01')
+        assert ca is not None, "Failed to create a baseCA object"
+        assert ca.isValid(), "baseCA isn't valid!"
+        assert ca.hasCertificate(), "No certificate created!"
+        ca.Reset()
+
+    def test05(self):
+        """ Testing signing request using a CA """
+        ca = baseCA.baseCA(baseDir='tests/ca/test01')
+        assert ca is not None, "Failed to create a baseCA object"
+        assert ca.isValid(), "baseCA isn't valid!"
+        req = CSRs.CSR(filename = 'tests/csr/test1.csr')
+        assert req is not None, "Invalid CSR object"
+        assert ca.signRequest(req) == 1, "Unable to sign a request"
 
 if __name__ == "__main__":
     unittest.main()

Added: labs/badca/tests/05LoggingTestCase.py
URL: http://svn.apache.org/viewvc/labs/badca/tests/05LoggingTestCase.py?rev=606690&view=auto
==============================================================================
--- labs/badca/tests/05LoggingTestCase.py (added)
+++ labs/badca/tests/05LoggingTestCase.py Mon Dec 24 02:52:33 2007
@@ -0,0 +1,47 @@
+import unittest
+
+from BaDCA import Logging
+from BaDCA.Testing import *
+
+class BaDCAbaseCATestCase(unittest.TestCase):
+
+    def test01(self):
+        """ Testing basic creation of Log instance """
+        l = Logging.Log()
+        assert l.isValid() == 0, "Log should be invalid!"
+        assert l.setDirectory('.') == 1, "Error setting directory"
+        assert l.setDirectory('foo') == 0, "Error, able to set to non-existant directory!"
+
+    def test02(self):
+        """ Test creation of a log file """
+        l = Logging.Log(directory = 'tests/logs', name='basic')
+        assert l.isValid(), "Log should be valid"
+        assert l.openLog() == 1, "Error opening log file"
+        assert l.closeLog() == 1, "Error closing log file"
+
+    def test03(self):
+        """ Test creation and writing to a log file with simple string"""
+        l = Logging.Log(directory = 'tests/logs', name='basic2')
+        assert l.isValid(), "Log should be valid"
+        assert l.openLog() == 1, "Error opening log file"
+        l.Log("Hello world")
+        assert l.closeLog() == 1, "Error closing log file"
+
+    def test04(self):
+        """ Test creation and writing to a log file with strings """
+        l = Logging.Log(directory = 'tests/logs', name='basic3')
+        assert l.isValid(), "Log should be valid"
+        assert l.openLog() == 1, "Error opening log file"
+        l.Log("%s %s", 'hello', 'world' )
+        assert l.closeLog() == 1, "Error closing log file"
+
+    def test05(self):
+        """ Test creation and writing to a log file with mixed types"""
+        l = Logging.Log(directory = 'tests/logs', name='basic4')
+        assert l.isValid(), "Log should be valid"
+        assert l.openLog() == 1, "Error opening log file"
+        l.Log("number = %d, string = '%s'", 123, 'hello world' )
+        assert l.closeLog() == 1, "Error closing log file"
+
+if __name__ == "__main__":
+    unittest.main()

Propchange: labs/badca/tests/ca/test01/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Mon Dec 24 02:52:33 2007
@@ -1,5 +1,5 @@
 private
-cert
+certs
 csr
 crl
 

Propchange: labs/badca/tests/logs/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Mon Dec 24 02:52:33 2007
@@ -0,0 +1,2 @@
+*.log
+

Modified: labs/badca/tests/runTests.py
URL: http://svn.apache.org/viewvc/labs/badca/tests/runTests.py?rev=606690&r1=606689&r2=606690&view=diff
==============================================================================
--- labs/badca/tests/runTests.py (original)
+++ labs/badca/tests/runTests.py Mon Dec 24 02:52:33 2007
@@ -16,15 +16,22 @@
 
     def __init__(self):
         self.fileMatcher = re.compile("^\S*TestCase\.py$")
+
         if len(sys.argv) < 2:
             self.exitUsage('You MUST supply a directory to scan')
         if not os.path.isdir(sys.argv[1]):
             self.exitUsage('You must supply a directory to scan')
+
         self.directory = os.path.abspath(sys.argv[1])
         files = os.listdir(self.directory)
+
+        self.cleanCA()
+        self.emptyDirectory('tests/logs')
+
         if len(sys.argv) > 2:
             self.filter = sys.argv[2:]
             print "Filtering tests to " + str(self.filter)
+        files.sort()
         for f in files:
             if self.fileMatcher.match(f):
                 m = re.compile("^\d{2}([A-Za-z]*)TestCase\.py").match(f)
@@ -56,7 +63,48 @@
         result = self.testRunner.run(tests)
         if not result.wasSuccessful():
             sys.exit(1)
- 
+
+    # In order to give consistent results we destroy the data created
+    # in order to test the CA code before we start.
+    def cleanCA(self):
+        caDir = os.path.join(self.directory, 'ca')
+        if not os.path.isdir(caDir):
+            os.mkdir(caDir)
+        testCA = [ 'test01' ]
+        for d in testCA:
+            theCADir = os.path.join(caDir, d)
+            if os.path.exists(theCADir) and os.path.isdir(theCADir):
+                print "Tidying up test CA '%s'" % d
+                self.cleanTheCA(theCADir)
+
+    # The CA tests create their directory structure and the various keys,
+    # certs and so on, so simply remove any that are left from previous
+    # tests.
+    def cleanTheCA(self, CAdir):
+        toRemove = [ 'certs', 'crl', 'csr', 'private' ]
+        for d in toRemove:
+            rDir = os.path.join(CAdir, d)
+            if os.path.isdir(rDir):
+                print "Removing %s" % rDir
+                self.removeDirectory(rDir)
+
+    # Recursively remove directories and their contents...
+    def removeDirectory(self, thedir):
+        self.emptyDirectory(thedir)
+        os.rmdir(thedir)
+
+    # Recursively remove directories and their contents, but leave the
+    # directory in place.
+    def emptyDirectory(self, thedir):
+        files = os.listdir(thedir)
+        for f in files:
+            fn = os.path.join(thedir, f)
+            print "  removing '%s' [%s]" % (f, fn)
+            if os.path.isdir(fn):
+                self.removeDirectory(fn)
+            else:
+                os.unlink(fn)
+
     def exitUsage(self, msg = None):
         print """
 Usage: runTests.py <directory>



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@labs.apache.org
For additional commands, e-mail: commits-help@labs.apache.org


Mime
View raw message