# -*- coding: utf-8 -*-
from OpenSSL import crypto, SSL
from socket import gethostname
from pprint import pprint
import time
from os.path import exists, join

def crt_import(str):
    return crypto.load_certificate(crypto.FILETYPE_PEM, open(str).read())

def key_import(str):
    return crypto.load_privatekey(crypto.FILETYPE_PEM, open(str).read())

def crt_write(crt, file):
    open(file, "wt").write(
        crypto.dump_certificate(crypto.FILETYPE_PEM, crt))

def key_write(key, file, cipher=None, passphrase=None):
    open(file, "wt").write(
        crypto.dump_privatekey(crypto.FILETYPE_PEM, key, cipher, passphrase) if cipher else crypto.dump_privatekey(crypto.FILETYPE_PEM, key))

def write((cert, key), cert_dir="."):
    common_name = cert.get_subject().CN
    CERT_FILE = "%s.crt" % common_name
    KEY_FILE = "%s.key" % common_name
    C_F = join(cert_dir, CERT_FILE)
    K_F = join(cert_dir, KEY_FILE)
    if not exists(C_F) or not exists(K_F):
        crt_write(cert,C_F)
        key_write(key,K_F)
    else:
         print "Les fichiers %s et %s existent déjà" % (C_F, K_F)

def crl_gen(crl=None, add_crt=[]):
    if not crl:
        crl=crypto.CRL()
    for crt in add_crt:
        revoked = crypto.Revoked()
        revoked.set_serial(hex(crt.get_serial_number()))
        crl.add_revoked(revoked)
    return crl

def crl_export(crl, (ca_cert, ca_key)):
    return crl.export(ca_cert, ca_key)

def crt_create(
  common_name,
  params={},
  not_after=365*24*3600,
  size=4096,
  key=None,
  parent=None,
  extentions=[]
  ):
    """
@param parent: tuple (X509 certificate, private key)
@return: (X509 certificate, private key)
"""
    params["CN"] = common_name # common name
    params.setdefault("C", "FR") # country
    params.setdefault("ST", "Val de Marne") # state
    params.setdefault("L", "Cachan") # city
    params.setdefault("O", "Association CRANS") # organization
    params.setdefault("OU", "") # organization unit

    if not key:
        # create a key pair
        k = crypto.PKey()
        k.generate_key(crypto.TYPE_RSA, size)
    else:
        k = key
    if k.bits() != size:
        raise ValueError("Key of %s bits but requesting %s bits" % (k.bits, size))

    # create a certificate
    cert = crypto.X509()
    cert.get_subject().C = params["C"]
    cert.get_subject().ST = params["ST"]
    cert.get_subject().L = params["L"]
    cert.get_subject().O = params["O"]
    if params["OU"]:
        cert.get_subject().OU = params["OU"]
    cert.get_subject().CN = params["CN"]

    cert.set_serial_number(int((time.time() - 1386340000)*100))
    cert.gmtime_adj_notBefore(0)
    cert.gmtime_adj_notAfter(not_after)
    cert.set_pubkey(k)
    cert.add_extensions(extentions)
    if parent:
        cert.set_issuer(parent[0].get_subject())
        cert.sign(parent[1], 'sha1')
    else:
        cert.set_issuer(cert.get_subject())
        cert.sign(k, 'sha1')
    
    return (cert, k)


def crt_ca_root_create(
  common_name,
  params={},
  size=4096,
  key=None,
  not_after=365*24*3600*10,
  ):
  extentions=[
    crypto.X509Extension("basicConstraints", True, "CA:TRUE"),
    crypto.X509Extension("keyUsage", True, "keyCertSign, cRLSign"),
  ]
  return crt_create(
  common_name,
  params,
  not_after,
  size,
  key,
  extentions=extentions
  )


def crt_ca_subroot_create(
  common_name,
  parent,
  params={},
  size=4096,
  key=None,
  not_after=365*24*3600*10,
  ):
  extentions=[
    crypto.X509Extension("basicConstraints", True, "CA:TRUE, pathlen:0"),
    crypto.X509Extension("keyUsage", True, "keyCertSign, cRLSign"),
  ]
  return crt_create(
  common_name,
  params,
  not_after,
  size,
  key,
  parent=parent,
  extentions=extentions
  )

def crt_client_create(
  common_name,
  parent,
  params={},
  size=4096,
  key=None,
  not_after=365*24*3600,
  alt_names=[]
  ):
  extentions=[
    crypto.X509Extension("basicConstraints", True, "CA:FALSE"),
    crypto.X509Extension("keyUsage", True, "digitalSignature, nonRepudiation, keyEncipherment"),
    crypto.X509Extension("nsCertType", True, "sslCA"),
    crypto.X509Extension("extendedKeyUsage", True, "clientAuth"),
#    crypto.X509Extension("crlDistributionPoints", False, "URI:http://myhost.com/myca.crl"),
  ]
  for name in alt_names:
      extentions.append(crypto.X509Extension("subjectAltName", True, "%s" % name))
  return crt_create(
  common_name,
  params,
  not_after,
  size,
  key,
  parent=parent,
  extentions=extentions
  )


def createCertRequest(pkey, digest="sha1", subjectAltName=[], **name):
    """
    Create a certificate request.
    Arguments: pkey   - The key to associate with the request
               digest - Digestion method to use for signing, default is md5
               **name - The name of the subject of the request, possible
                        arguments are:
                          C     - Country name
                          ST    - State or province name
                          L     - Locality name
                          O     - Organization name
                          OU    - Organizational unit name
                          CN    - Common name
                          emailAddress - E-mail address
    Returns:   The certificate request in an X509Req object
    """
    req = crypto.X509Req()
    subj = req.get_subject()
    for (key,value) in name.items():
        setattr(subj, key, value)
    exts = []
    if subjectAltName:
        exts.append(crypto.X509Extension("subjectAltName", False, ", ".join(["DNS:%s" % altName for altName in subjectAltName])))
    if exts:
        req.add_extensions(exts)
    req.set_pubkey(pkey)
    req.sign(pkey, digest)
    return req

