package CertificateManager

import "C"
import (
	"Sunny/Certificate"
	"Sunny/Certificate/pkcs"
	"crypto/rand"
	"crypto/rsa"
	"crypto/tls"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/pem"
	"errors"
	"fmt"
	"math/big"
	"net"
	"time"
)

func AddP12Certificate(privateKeyName, privatePassword string) (*tls.Certificate, string, string, error) {
	return Certificate.AddP12Certificate(privateKeyName, privatePassword)
}

func LoadX509KeyPair(capath, keypath string) (bool, *tls.Certificate) {
	a, e := tls.LoadX509KeyPair(capath, keypath)
	if e != nil {
		return false, nil
	}
	return true, &a
}

func LoadX509Certificate(host string, ca, key []byte) (bool, *tls.Certificate) {
	c, err := loadRootCa(ca)
	if err != nil {
		return false, nil
	}
	k, err := loadRootKey(key)
	if err != nil {
		return false, nil
	}
	a, b, e := generatePem(host, c, k)
	if e != nil {
		return false, nil
	}
	cer, err := tls.X509KeyPair(a, b)
	if err != nil {
		return false, nil
	}
	return true, &cer
}

var max = new(big.Int).Lsh(big.NewInt(1), 128)

func generatePem(host string, rootca *x509.Certificate, rootkey *rsa.PrivateKey) ([]byte, []byte, error) {
	//max := new(big.Int).Lsh(big.NewInt(1), 128)   //把 1 左移 128 位，返回给 big.Int
	serialNumber, _ := rand.Int(rand.Reader, max) //返回在 [0, max) 区间均匀随机分布的一个随机值
	template := x509.Certificate{
		SerialNumber: serialNumber, // SerialNumber 是 CA 颁布的唯一序列号，在此使用一个大随机数来代表它
		Subject: pkix.Name{ //Name代表一个X.509识别名。只包含识别名的公共属性，额外的属性被忽略。
			CommonName: host,
		},
		NotBefore:      time.Now().AddDate(-1, 0, 0),
		NotAfter:       time.Now().AddDate(1, 0, 0),
		KeyUsage:       x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, //KeyUsage 与 ExtKeyUsage 用来表明该证书是用来做服务器认证的
		ExtKeyUsage:    []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},               // 密钥扩展用途的序列
		EmailAddresses: []string{"forward.nice.cp@gmail.com"},
	}

	if ip := net.ParseIP(host); ip != nil {
		template.IPAddresses = []net.IP{ip}
	} else {
		template.DNSNames = []string{host}
	}

	priKey := rootkey

	cer, err := x509.CreateCertificate(rand.Reader, &template, rootca, &priKey.PublicKey, rootkey)
	if err != nil {
		return nil, nil, err
	}

	return pem.EncodeToMemory(&pem.Block{ // 证书
			Type:  "CERTIFICATE",
			Bytes: cer,
		}), pem.EncodeToMemory(&pem.Block{ // 私钥
			Type:  "RSA PRIVATE KEY",
			Bytes: x509.MarshalPKCS1PrivateKey(priKey),
		}), err
}

// 加载根Private Key
func loadRootKey(root_Key []byte) (*rsa.PrivateKey, error) {
	p, _ := pem.Decode(root_Key)
	if p == nil {
		return nil, errors.New("parse Key Fail ")
	}
	rootKey, err := x509.ParsePKCS1PrivateKey(p.Bytes)
	if err != nil {
		return nil, err
	}
	return rootKey, nil
}

// 加载根证书
func loadRootCa(root_Ca []byte) (*x509.Certificate, error) {
	p, _ := pem.Decode(root_Ca)
	if p == nil {
		return nil, errors.New("parse ca Fail ")
	}
	rootCa, err := x509.ParseCertificate(p.Bytes)
	if err != nil {
		return nil, err
	}
	return rootCa, nil
}

func CreateCA(Country, Organization, OrganizationalUnit, Province, CommonName, Locality string, bits, NotAfter int) (ca, key []byte, e error) {
	var NullBytes = []byte{}
	caPrivkey, err := rsa.GenerateKey(rand.Reader, bits)
	//caPrivkey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
	if err != nil {
		return NullBytes, NullBytes, err
	}
	serialNumber, _ := rand.Int(rand.Reader, max) //返回在 [0, max) 区间均匀随机分布的一个随机值

	template := &x509.Certificate{
		SerialNumber: serialNumber, // SerialNumber 是 CA 颁布的唯一序列号，在此使用一个大随机数来代表它
		Subject: pkix.Name{ // 证书的主题信息
			Country:            []string{Country},            // 证书所属的国家
			Organization:       []string{Organization},       // 证书存放的公司名称
			OrganizationalUnit: []string{OrganizationalUnit}, // 证书所属的部门名称
			Province:           []string{Province},           // 证书签发机构所在省
			CommonName:         CommonName,                   // 证书域名
			Locality:           []string{Locality},           // 证书签发机构所在市
		},
		NotBefore:             time.Now(),
		NotAfter:              time.Now().AddDate(0, 0, NotAfter),
		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, // 典型用法是指定叶子证书中的公钥的使用目的。它包括一系列的OID，每一个都指定一种用途。例如{id pkix 31}表示用于服务器端的TLS/SSL连接；{id pkix 34}表示密钥可以用于保护电子邮件。
		KeyUsage:              x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,                      // 指定了这份证书包含的公钥可以执行的密码操作，例如只能用于签名，但不能用来加密
		IsCA:                  true,                                                                       // 指示证书是不是ca证书
		BasicConstraintsValid: true,                                                                       // 指示证书是不是ca证书
	}

	// 生成自签证书(template=parent)
	rootCertDer, err := x509.CreateCertificate(rand.Reader, template, template, &caPrivkey.PublicKey, caPrivkey) //DER 格式
	if err != nil {
		return NullBytes, NullBytes, err
	}
	caPrivBytes := x509.MarshalPKCS1PrivateKey(caPrivkey)

	rootKey := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: caPrivBytes})
	if len(rootKey) < 1 {
		return NullBytes, NullBytes, errors.New("Generate Key Fail. ")
	}
	rootCert := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: rootCertDer})
	if len(rootKey) < 1 {
		return NullBytes, NullBytes, errors.New("Generate CERTIFICATE Fail. ")
	}

	return rootCert, rootKey, err
}

func CertToP12(certBuf, keyBuf, Pwd string) (p12Cert []byte, err error) {

	caBlock, _ := pem.Decode([]byte(certBuf))
	crt, err := x509.ParseCertificate(caBlock.Bytes)
	if err != nil {
		err = fmt.Errorf("证书解析异常, Error : %v", err)
		return
	}

	keyBlock, _ := pem.Decode([]byte(keyBuf))
	priKey, err := x509.ParsePKCS1PrivateKey(keyBlock.Bytes)
	if err != nil {
		err = fmt.Errorf("证书密钥解析key异常, Error : %v", err)
		return
	}

	pfx, err := pkcs.Encode(rand.Reader, priKey, crt, nil, Pwd)
	if err != nil {
		err = fmt.Errorf("pem to p12 转换证书异常, Error : %v", err)
		return
	}

	return pfx, err

}
