#!/usr/bin/env python
#
#vim: ts=4 sw=4 nowrap
#
from __future__ import print_function

"""PKI demo by Peter Teniz <peter.teniz@inverisa.net>"""

from M2Crypto import ASN1, EVP, RSA, X509, m2


MBSTRING_FLAG = 0x1000
MBSTRING_ASC  = MBSTRING_FLAG | 1
MBSTRING_BMP  = MBSTRING_FLAG | 2


class Cert(object):
    def __init__ ( self ):
        self.RsaKey = { 'KeyLength'       : 1024,
                        'PubExponent'     : 0x10001,        # -> 65537
                        'keygen_callback' : self.callback
                      }

        self.KeyPair         = None
        self.PKey            = None

        self.X509Request     = None
        self.X509Certificate = None

    def callback ( self, *args ):
        return 'p'



    def CreatePKey ( self ):
        self.KeyPair = RSA.gen_key( self.RsaKey['KeyLength'], self.RsaKey['PubExponent'], self.RsaKey['keygen_callback'] )
        #PubKey = RSA.new_pub_key( self.KeyPair.pub () )

        self.KeyPair.save_key( 'KeyPair.pem', cipher='des_ede3_cbc', callback=self.callback )

        self.PKey = EVP.PKey ( md='sha1')
        self.PKey.assign_rsa ( self.KeyPair )


    def CreateX509Request ( self ):
        #
        # X509 REQUEST
        #

        self.X509Request = X509.Request ()

        #
        # subject
        #

        X509Name = X509.X509_Name ()

        X509Name.add_entry_by_txt ( field='C',            type=MBSTRING_ASC, entry='austria',               len=-1, loc=-1, set=0 )    # country name
        X509Name.add_entry_by_txt ( field='SP',           type=MBSTRING_ASC, entry='kernten',               len=-1, loc=-1, set=0 )    # state of province name
        X509Name.add_entry_by_txt ( field='L',            type=MBSTRING_ASC, entry='stgallen',              len=-1, loc=-1, set=0 )    # locality name
        X509Name.add_entry_by_txt ( field='O',            type=MBSTRING_ASC, entry='labor',                 len=-1, loc=-1, set=0 )    # organization name
        X509Name.add_entry_by_txt ( field='OU',           type=MBSTRING_ASC, entry='it-department',         len=-1, loc=-1, set=0 )    # organizational unit name
        X509Name.add_entry_by_txt ( field='CN',           type=MBSTRING_ASC, entry='Certificate client',    len=-1, loc=-1, set=0 )    # common name
        X509Name.add_entry_by_txt ( field='Email',        type=MBSTRING_ASC, entry='user@localhost',        len=-1, loc=-1, set=0 )    # pkcs9 email address
        X509Name.add_entry_by_txt ( field='emailAddress', type=MBSTRING_ASC, entry='user@localhost',        len=-1, loc=-1, set=0 )    # pkcs9 email address

        self.X509Request.set_subject_name( X509Name )

        #
        # publickey
        #

        self.X509Request.set_pubkey ( pkey=self.PKey )
        self.X509Request.sign ( pkey=self.PKey, md='sha1' )
        #print(X509Request.as_text ())






    def CreateX509Certificate ( self ):
        #
        # X509 CERTIFICATE
        #

        self.X509Certificate =  X509.X509 ()

        #
        # version
        #

        self.X509Certificate.set_version ( 0 )

        #
        # time notBefore
        #

        ASN1 = ASN1.ASN1_TIME ()
        ASN1.set_time ( 500 )
        self.X509Certificate.set_not_before( ASN1 )

        #
        # time notAfter
        #

        ASN1 = ASN1.ASN1_TIME ()
        ASN1.set_time ( 500 )
        self.X509Certificate.set_not_after( ASN1 )

        #
        # public key
        #

        self.X509Certificate.set_pubkey ( pkey=self.PKey )

        #
        # subject
        #

        X509Name = self.X509Request.get_subject ()

        #print(X509Name.entry_count ())
        #print(X509Name.as_text ())

        self.X509Certificate.set_subject_name( X509Name )

        #
        # issuer
        #

        X509Name = X509.X509_Name ( m2.x509_name_new () )

        X509Name.add_entry_by_txt ( field='C',            type=MBSTRING_ASC, entry='germany',               len=-1, loc=-1, set=0 )    # country name
        X509Name.add_entry_by_txt ( field='SP',           type=MBSTRING_ASC, entry='bavaria',               len=-1, loc=-1, set=0 )    # state of province name
        X509Name.add_entry_by_txt ( field='L',            type=MBSTRING_ASC, entry='munich',                len=-1, loc=-1, set=0 )    # locality name
        X509Name.add_entry_by_txt ( field='O',            type=MBSTRING_ASC, entry='sbs',                   len=-1, loc=-1, set=0 )    # organization name
        X509Name.add_entry_by_txt ( field='OU',           type=MBSTRING_ASC, entry='it-department',         len=-1, loc=-1, set=0 )    # organizational unit name
        X509Name.add_entry_by_txt ( field='CN',           type=MBSTRING_ASC, entry='Certificate Authority', len=-1, loc=-1, set=0 )    # common name
        X509Name.add_entry_by_txt ( field='Email',        type=MBSTRING_ASC, entry='admin@localhost',       len=-1, loc=-1, set=0 )    # pkcs9 email address
        X509Name.add_entry_by_txt ( field='emailAddress', type=MBSTRING_ASC, entry='admin@localhost',       len=-1, loc=-1, set=0 )    # pkcs9 email address

        #print(X509Name.entry_count ())
        #print(X509Name.as_text ())

        self.X509Certificate.set_issuer_name( X509Name )

        #
        # signing
        #

        self.X509Certificate.sign( pkey=self.PKey, md='sha1' )
        print(self.X509Certificate.as_text ())





if __name__ == '__main__':
    run = Cert ()
    run.CreatePKey ()
    run.CreateX509Request ()
    run.CreateX509Certificate ()
