# -*- coding: utf-8 -*-

# Copyright 2012-2016 Mir Calculate. http://www.calculate-linux.org
#
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.

import sys
from M2Crypto import RSA, X509, EVP, m2
from calculate.lib.cl_lang import setLocalTranslate
from binascii import hexlify
import hashlib

'''
Copyright (c) 2016 Jesse Peterson
Licensed under the MIT license. See the included LICENSE.txt file for details.
'''
 
from M2Crypto import m2
from M2Crypto.X509 import X509_Extension
from ctypes import *
 

_ = lambda x: x
setLocalTranslate('cl_core3', sys.modules[__name__])


def passphrase_callback(v):
    return ""


def generateRSAKey():
    return RSA.gen_key(2048, m2.RSA_F4)


def makePKey(key):
    pkey = EVP.PKey()
    pkey.assign_rsa(key)
    return pkey


def makeRequest(pubkey, pkey, serv_host, port):
    """ create query to the signing on server """
    req = X509.Request()
    # Seems to default to 0, but we can now set it as well, so just API test
    req.set_version(req.get_version())
    req.set_pubkey(pkey)
    name = X509.X509_Name()
    c = raw_input(_("Enter the certificate date manually? [y]/n: "))
    if c.lower() in ['n', 'no']:
        name.CN = 'root_cert'  # (Common Name);
        name.OU = 'www.calculate-linux.ru'  # (Organization Unit);
        name.O = 'calculate-linux'  # (Organization Name);
        name.L = ''  # (Locality Name);
        name.ST = 'Spb'  # (State Name);
        name.C = 'En'  # (Country);
    else:
        import socket

        print _('Do not use spaces or tabs.')
        host_name = socket.getfqdn()
        # if serv_host == host_name:
        # print '\n'+_("Want to create self-signed certificate?\n"
        # "Use key --gen-cert-self")
        # return None
        if serv_host in host_name:
            host_name = host_name.replace('.' + serv_host, '')
            list_host_name = host_name.split('.')
            print 'list_host_name = ', list_host_name
            result_host_name = \
                list_host_name[len(list_host_name) - 1] + "." + serv_host
        else:
            host_name = socket.getfqdn()
            list_host_name = host_name.split('.')
            result_host_name = list_host_name[0] + "." + serv_host
        name.CN = raw_input(_('Hostname [%s] : ') % result_host_name)
        if name.CN in ['', None]:
            name.CN = result_host_name
        name.OU = raw_input(_('Organization unit: '))
        if not name.OU:
            name.OU = ''
        else:
            name.OU.replace(' ', '_').replace('\t', '_')
        name.O = raw_input(_('Organization name: '))
        if not name.O:
            name.O = ''
        else:
            name.O.replace(' ', '_').replace('\t', '_')
        network = _('Full network address (host:port)')
        name.L = raw_input(network + ' [%s:%d]: ' % (host_name, port))
        if name.L in ['', None]:
            name.L = host_name + ':' + str(port)
        name.ST = raw_input(_('City: '))
        if not name.ST:
            name.ST = ''
        else:
            name.ST.replace(' ', '_').replace('\t', '_')
        name.C = raw_input(_('Country (two letters only!): '))

    req.set_subject_name(name)
    ext1 = X509.new_extension('nsComment', 'Auto Generated')
    extstack = X509.X509_Extension_Stack()
    extstack.push(ext1)
    req.add_extensions(extstack)
    req.sign(pkey, 'md5')
    return req

class CreateCertError(Exception):
    pass

def create_selfsigned_ca(dn_data, keyfile, certfile):
    from calculate.lib.utils.gpg import Pipe
    from calculate.lib.utils.files import process
    from string import Template
    ca_conf = Template("""
[ req ]
default_bits = 2048
distinguished_name = req_distinguished_name
prompt = no
x509_extensions = v3_ca

[ req_distinguished_name ]
CN = $CN
ST = $ST
L = $L
O = $O
OU = $OU

[ v3_ca ]
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer
basicConstraints = critical,CA:true
""")
    with Pipe() as cfgpipe:
        p = process("openssl", "req", "-x509", "-new", "-key", keyfile,
                    "-config", cfgpipe.get_filename(), "-out", certfile,
                    "-days", "7300")
        cfgpipe.write(ca_conf.safe_substitute(dn_data))
        cfgpipe.closein()
        if p.failed():
            raise CreateCertError(p.readerr())

def sign_client_certifacation_request(ca_keyfile, ca_certfile, requestfile, out_cert, group):
    from calculate.lib.utils.gpg import Pipe
    from calculate.lib.utils.files import process
    from string import Template
    client_conf = Template("""
[ client ]
nsCertType = client
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth
nsComment = group:$group
""")
    with Pipe() as cfgpipe:
        p = process("openssl", "x509", "-req", "-in", requestfile,
                    "-CA", ca_certfile,
                    "-CAkey", ca_keyfile, "-CAcreateserial",
                    "-extfile", cfgpipe.get_filename(),
                    "-extensions", "client",
                    "-out", out_cert,
                    "-days", "7300")
        cfgpipe.write(client_conf.safe_substitute({"group":group}))
        cfgpipe.closein()
        if p.failed():
            raise CreateCertError(p.readerr())
