Golang1.7.3使用x509標準庫創建自簽名證書和簽發名其他證書

主代碼:
package rsa

import (
    "crypto/rand"
    "crypto/rsa"
    "crypto/x509"
    "crypto/x509/pkix"
    "encoding/pem"
    "io/ioutil"
    "math/big"
    rd "math/rand"
    "os"
    "time"
)

func init() {
    rd.Seed(time.Now().UnixNano())
}

type CertInformation struct {
    Country            []string
    Organization       []string
    OrganizationalUnit []string
    EmailAddress       []string
    Province           []string
    Locality           []string
    CommonName         string
    CrtName, KeyName   string
    IsCA               bool
    Names              []pkix.AttributeTypeAndValue
}

func CreateCRT(RootCa *x509.Certificate, RootKey *rsa.PrivateKey, info CertInformation) error {
    Crt := newCertificate(info)
    Key, err := rsa.GenerateKey(rand.Reader, 2048)
    if err != nil {
        return err
    }

    var buf []byte
    if RootCa == nil || RootKey == nil {
        //創建自簽名證書
        buf, err = x509.CreateCertificate(rand.Reader, Crt, Crt, &Key.PublicKey, Key)
    } else {
        //使用根證書籤名
        buf, err = x509.CreateCertificate(rand.Reader, Crt, RootCa, &Key.PublicKey, RootKey)
    }
    if err != nil {
        return err
    }

    err = write(info.CrtName, "CERTIFICATE", buf)
    if err != nil {
        return err
    }

    buf = x509.MarshalPKCS1PrivateKey(Key)
    return write(info.KeyName, "PRIVATE KEY", buf)
}
//編碼寫入文件
func write(filename, Type string, p []byte) error {
    File, err := os.Create(filename)
    defer File.Close()
    if err != nil {
        return err
    }
    var b *pem.Block = &pem.Block{Bytes: p, Type: Type}
    return pem.Encode(File, b)
}

func Parse(crtPath, keyPath string) (rootcertificate *x509.Certificate, rootPrivateKey *rsa.PrivateKey, err error) {
    rootcertificate, err = ParseCrt(crtPath)
    if err != nil {
        return
    }
    rootPrivateKey, err = ParseKey(keyPath)
    return
}

func ParseCrt(path string) (*x509.Certificate, error) {
    buf, err := ioutil.ReadFile(path)
    if err != nil {
        return nil, err
    }
    p := &pem.Block{}
    p, buf = pem.Decode(buf)
    return x509.ParseCertificate(p.Bytes)
}

func ParseKey(path string) (*rsa.PrivateKey, error) {
    buf, err := ioutil.ReadFile(path)
    if err != nil {
        return nil, err
    }
    p, buf := pem.Decode(buf)
    return x509.ParsePKCS1PrivateKey(p.Bytes)
}

func newCertificate(info CertInformation) *x509.Certificate {
    return &x509.Certificate{
        SerialNumber: big.NewInt(rd.Int63()),
        Subject: pkix.Name{
            Country:            info.Country,
            Organization:       info.Organization,
            OrganizationalUnit: info.OrganizationalUnit,
            Province:           info.Province,
            CommonName:         info.CommonName,
            Locality:           info.Locality,
            ExtraNames:         info.Names,
        },
        NotBefore:             time.Now(),//證書的開始時間
        NotAfter:              time.Now().AddDate(20, 0, 0),//證書的結束時間
        BasicConstraintsValid: true, //基本的有效性約束
        IsCA:           info.IsCA,   //是否是根證書
        ExtKeyUsage:    []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},    //證書用途
        KeyUsage:       x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
        EmailAddresses: info.EmailAddress,
    }
}
測試代碼:
package rsa

import (
    "crypto/x509/pkix"
    "encoding/asn1"
    "os"
    "testing"
)

func Test_crt(t *testing.T) {
    baseinfo := CertInformation{Country: []string{"CN"}, Organization: []string{"WS"}, IsCA: true,
        OrganizationalUnit: []string{"work-stacks"}, EmailAddress: []string{"[email protected]"},
        Locality: []string{"SuZhou"}, Province: []string{"JiangSu"}, CommonName: "Work-Stacks",
        CrtName: "test_root.crt", KeyName: "test_root.key"}

    err := CreateCRT(nil, nil, baseinfo)
    if err != nil {
        t.Log("Create crt error,Error info:", err)
        return
    }
    crtinfo := baseinfo
    crtinfo.IsCA = false
    crtinfo.CrtName = "test_server.crt"
    crtinfo.KeyName = "test_server.key"
    crtinfo.Names = []pkix.AttributeTypeAndValue{{asn1.ObjectIdentifier{2, 1, 3}, "MAC_ADDR"}} //添加擴展字段用來做自定義使用

    crt, pri, err := Parse(baseinfo.CrtName, baseinfo.KeyName)
    if err != nil {
        t.Log("Parse crt error,Error info:", err)
        return
    }
    err = CreateCRT(crt, pri, crtinfo)
    if err != nil {
        t.Log("Create crt error,Error info:", err)
    }
    os.Remove(baseinfo.CrtName)
    os.Remove(baseinfo.KeyName)
    os.Remove(crtinfo.CrtName)
    os.Remove(crtinfo.KeyName)
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章