激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

腳本之家,腳本語言編程技術及教程分享平臺!
分類導航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服務器之家 - 腳本之家 - Golang - golang開發及數字證書研究分享

golang開發及數字證書研究分享

2021-12-03 13:15秋天的春 Golang

這篇文章主要為大家介紹了golang開發以及數字證書的研究示例分享,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步

在go語言提供的系統包中包含了大量和數字證書有關的方法。在這些方法中就有私鑰生成的方法、私鑰解析的方法、證書請求生成的方法、證書生成的方法等等。通過這些方法應該能夠實現和openssl命令類似的功能。

仿照openssl生成證書的流程(從私鑰的生成—>證書請求的生成—>證書的生成)用go語言進行模擬。

私鑰的生成

在go的x509包下有go定義的證書的結構,該結構如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
Raw                     []byte // Complete ASN.1 DER content (certificate, signature algorithm and signature).
RawTBSCertificate       []byte // Certificate part of raw ASN.1 DER content.
RawSubjectPublicKeyInfo []byte // DER encoded SubjectPublicKeyInfo.
RawSubject              []byte // DER encoded Subject
RawIssuer               []byte // DER encoded Issuer
Signature          []byte
SignatureAlgorithm SignatureAlgorithm
PublicKeyAlgorithm PublicKeyAlgorithm
PublicKey          interface{}
Version             int
SerialNumber        *big.Int
Issuer              pkix.Name
Subject             pkix.Name
NotBefore, NotAfter time.Time // Validity bounds.
KeyUsage            KeyUsage
Extensions []pkix.Extension
ExtraExtensions []pkix.Extension
UnhandledCriticalExtensions []asn1.ObjectIdentifier
ExtKeyUsage        []ExtKeyUsage           // Sequence of extended key usages.
UnknownExtKeyUsage []asn1.ObjectIdentifier // Encountered extended key usages unknown to this package.
BasicConstraintsValid bool // if true then the next two fields are valid.
IsCA                  bool
MaxPathLen            int
MaxPathLenZero bool
 
SubjectKeyId   []byte
AuthorityKeyId []byte
OCSPServer            []string
IssuingCertificateURL []string
 
// Subject Alternate Name values
DNSNames       []string
EmailAddresses []string
IPAddresses    []net.IP
PermittedDNSDomainsCritical bool // if true then the name constraints are marked critical.
PermittedDNSDomains         []string
CRLDistributionPoints []string
PolicyIdentifiers []asn1.ObjectIdentifier

在該結構中有PublicKeyAlgorithm字段,該字段用來表示生成公鑰的算法。該字段的變量中可使用的字段如下:

?
1
2
3
4
5
6
const (
        UnknownPublicKeyAlgorithm PublicKeyAlgorithm = iota
        RSA
        DSA
        ECDSA
)

一共定義了4中情況。除去Unknown的情況。剩下的三種的實現分別在crypto/rsacrypto/dsacrypto/ecdsa這三個包中定義了實現。

RSA

使用RSA方法生成公私鑰的方式非常簡單。在crypto/rsa包中直接提供了生成方法。

?
1
func GenerateKey(random io.Reader, bits int) (*PrivateKey, error)

該方法生成一個rsa的私鑰。查找整個包所提供的方法并沒有什么方法能夠生成公鑰。但在包中有公鑰的結構說明。查看私鑰的結構:

?
1
2
3
4
5
6
type PrivateKey struct {
        PublicKey            // public part.
        D         *big.Int   // private exponent
        Primes    []*big.Int // prime factors of N, has >= 2 elements.
        Precomputed PrecomputedValues
}

赫然發現,公鑰包含在私鑰的結構中。換句話說,只要生成的私鑰,公鑰就同時擁有了(ECDSA和DSA的公鑰也是如此)。

ECDSA

使用ECDSA生成公私鑰的方式和RSA的方式非常類似:

?
1
func GenerateKey(c elliptic.Curve, rand io.Reader) (*PrivateKey, error)

crypto/elliptic為參數c提供了4中實現方式。分別為:

?
1
2
3
4
func P224() Curve
func P256() Curve
func P384() Curve
func P521() Curve

DSA

使用DSA生成公私鑰的方式和上面兩種有些不同:

?
1
func GenerateKey(priv *PrivateKey, rand io.Reader) error

私鑰并不是作為結果返回,而是作為參數傳入。那很簡單,我直接初始化一個DSA的私鑰,然后把該私鑰作為參數傳入不就可以了嘛。事實是,僅僅是實例化了一個DSA的私鑰是無法完成公私鑰的生成的。生成的結果如下:

?
1
priv:&{PublicKey:{Parameters:{P:<nil> Q:<nil> G:<nil>} Y:<nil>} X:<nil>}

可以發現公鑰中的所有內容都是為nil(空),由此可以說明無法只通過GenerateKey()方法生成DSA的私鑰。

crypto/dsa包中還提供了:

?
1
func GenerateParameters(params *Parameters, rand io.Reader, sizes ParameterSizes) error

通過該方法的描述,可以了解到該方法是為DSA設置參數。那又如何和公私鑰有關呢?,在DSA的私鑰結構中包含公鑰,在公鑰的結構中就包含該方法所需要傳入的參數Parameters。由此,我便想到可以先使用該方法對一些參數進行初始化,然后再生成私鑰。

?
1
2
3
priv := &dsa.PrivateKey{}
dsa.GenerateParameters(&priv.Parameters, rand.Reader, dsa.L1024N160)
dsa.GenerateKey(priv, rand.Reader)

生成的私鑰內容如下:

?
1
priv:&{PublicKey:{Parameters:{P:+91268520972047344779510472614939006285152176630742165979533208518526258287540244526987668731096217967904150874969731516661412604963023247030101570715552650277776208098462838867711078025572452557692674802977527475661989210578136725258241385474445330497234586673407237238372329018550727884900161895964574509801 Q:+767580094855879488293276223470508701563202760721 G:+42393651221310072390273970570719382707264443685255379637082820177806079494092036767507554061381644533127114802103872901363724639317297276457243780033980909021336576570837756106975221868617534717069925676009421223798208864916837561389117514471387385853288499961716794226875046226553216578582138687489881455573} Y:+68767508229940365112562020548287141674708444377336699267991474890690034611201698420418573204906537903040876819582645033160073997940957577512216430788561800033703926395782022182868300960590402743043934344374390498368316144177816214923367214895567903510165216432049170686626889267028482641530556275670781873053} X:+628682865942164859869306394087148223993136336500}

注意:Golang 對DSA證書沒有完整的支持。

給私鑰上鎖(加訪問密碼)

在使用openssl進行私鑰生成的時候,openssl需要我提供私鑰的訪問密碼。那使用go進行私鑰時,應該也有該功能。那應該在什么時候添加這個密碼呢?是在生成私鑰的時候,還是在生成pem文件的時候。我首先想到的是在生成秘密的時候,但是在crypto/rsacrypto/dsacrypto/ecdsa這三個包中查找時并沒有發現任何和密碼有關的詞眼。那就應該在生成pem文件的時候加上密碼。生成pem文件的方法在encoding/pem這個包中。但該包中只有兩個編碼,一個解碼的方法,和密碼有沒有任何關系,唯一的存在的關系就是Block結構中的Header字段。

使用openssl生成的私鑰文件中會存在這樣的字段:

?
1
2
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,02a0ba59e8cfd431

使用該字段來說明使用加密方式和提供用于解密的初始值向量。

在生成私鑰和生成文件都無法把密碼添加進去。那我就在想是否是在得到私鑰的時候對私鑰的byte數組進行加密。但這樣就需要自己實現了。講道理的話,go應該會為這種普遍性的東西提供已經封裝好的方法。來回重新看api文檔。發現自己漏看一個非常重要的包crypto/x509。在該包提供的方法中。很輕松的就找到了如下兩個方法:

?
1
2
func DecryptPEMBlock(b *pem.Block, password []byte) ([]byte, error)
func EncryptPEMBlock(rand io.Reader, blockType string, data, password []byte, alg PEMCipher) (*pem.Block, error)

在這兩個方法中又要pem,password,恩應該就是這兩個方法了,正好一個生成一個解析。

同在x509包下提供了:

?
1
2
func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte
func MarshalECPrivateKey(key *ecdsa.PrivateKey) ([]byte, error)

把RSA和ECDSA私鑰轉換成byte數組的方法,但是沒有找到把DSA私鑰轉換成byte數組的方法。

生成證書請求

證書請求生成很簡單在crypto/x509中直接提供了現成的方法。

?
1
func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv interface{}) (csr []byte, err error)

但使用用該方法有一個限制條件:

?
1
All keys types that are implemented via crypto.Signer are supported (This includes *rsa.PublicKey and *ecdsa.PublicKey.)

無法使用*dsa.PublicKey類型的公鑰。而傳入的參數是一個私鑰,因此無法使用dsa類型的私鑰。

go對dsa類型的證書

該方法需要通過一個證書請求的模板,在go中CertificateRequest是如下定義的:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Raw                      []byte // Complete ASN.1 DER content (CSR, signature algorithm and signature).
RawTBSCertificateRequest []byte // Certificate request info part of raw ASN.1 DER content.
RawSubjectPublicKeyInfo  []byte // DER encoded SubjectPublicKeyInfo.
RawSubject               []byte // DER encoded Subject.
Version            int
Signature          []byte
SignatureAlgorithm SignatureAlgorithm
PublicKeyAlgorithm PublicKeyAlgorithm
PublicKey          interface{}
Subject pkix.Name
Attributes []pkix.AttributeTypeAndValueSET
Extensions []pkix.Extension
ExtraExtensions []pkix.Extension
DNSNames       []string
EmailAddresses []string
IPAddresses    []net.IP

有一些內容可以不用填寫。如果填寫了,在后面生成證書時將作為內容直接填入,我就根據openssl生成證書請求時在控制臺所展現的內容進行填寫。即添加Subject中的內容。Subject是這樣定義的:

?
1
2
3
4
5
6
7
8
9
type Name struct {
        Country, Organization, OrganizationalUnit []string
        Locality, Province                        []string
        StreetAddress, PostalCode                 []string
        SerialNumber, CommonName                  string
 
        Names      []AttributeTypeAndValue
        ExtraNames []AttributeTypeAndValue
}

生成證書

在go提供的crypto/x509包下并沒有生成CA的方法,生成證書的方法也只有一個方法:

?
1
func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv interface{}) (cert []byte, err error)

它的參數中使用的是兩個證書,和我們之前生成的CertificateRequest沒有關系,而且在整個crypto/x509中的方法中都沒有找到把CertificateRequest轉換成Certificate的方法,而且CertificateRequest和Certificate中的部分數據結構是一樣的,因此猜想是通過把CertificateRequest中的部分內容復制到Certificate中。然后再通過CreateCertificate進行簽發。

如果傳入的兩個證書參數是一樣的,那么生成的證書是一張自簽發的根證書。如果傳入的兩張證書不同,生成的就是普通的證書了。使用的公鑰和私鑰是簽發者的公私鑰即參數parent的公私鑰。和生成CertificateRequest一樣,在這個方法中使用的公私鑰不能是DSA類型的。

設置CA

在Certificate這個結構體中有IsCA這個字段。用來標識該證書是CA證書,但是在設置該字段為true后生成的證書在擴展中并沒有顯示這個證書是CA證書的。原因是在如果要使IsCA生效,需要設置BasicConstraintsValid也為true。同樣的也適用于MaxPathLen這個字段。

簽名算法的選擇

在go中為證書的簽名算法提供了常見的類型:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
UnknownSignatureAlgorithm SignatureAlgorithm = iota
MD2WithRSA
MD5WithRSA
SHA1WithRSA
SHA256WithRSA
SHA384WithRSA
SHA512WithRSA
DSAWithSHA1
DSAWithSHA256
ECDSAWithSHA1
ECDSAWithSHA256
ECDSAWithSHA384
ECDSAWithSHA512

在生成證書的時候我直接選擇的SHA1WITHRSA,應為我的私鑰是通過RSA算法生成的,沒有任何問題,但是在看go的源碼中有一段生成自簽名證書的測試方法。在該方法中使用了其他的簽名算法。因此我想,這些簽名算法的應該如何選擇。當我把簽名算法改成ECDSAWITHSHA1的時候,在進行簽名的時候,出現了簽名錯誤。

因此我猜猜簽名算法的選擇需要和簽署者的公私鑰的生成方式有關。

代碼時間

一切用代碼說話。

和生成私鑰有關:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
func GenRSAPriv(fileName, passwd string, len int) error {
    priv, err := rsa.GenerateKey(rand.Reader, len)
    if err != nil {
        return err
    }
 
    data := x509.MarshalPKCS1PrivateKey(priv)
    err = encodePrivPemFile(fileName, passwd, data)
    return err
}
//GenECDSAPriv 生成ECDSA私鑰文件
func GenECDSAPriv(fileName, passwd string) error {
    priv, err := ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
    if err != nil {
        return err
    }
    data, err := x509.MarshalECPrivateKey(priv)
    if err != nil {
        return err
    }
    err = encodePrivPemFile(fileName, passwd, data)
    return err
}
//GenDSAPriv 生成DSA私鑰(用于演示)
func GenDSAPriv() {
    priv := &dsa.PrivateKey{}
    dsa.GenerateParameters(&priv.Parameters, rand.Reader, dsa.L1024N160)
    dsa.GenerateKey(priv, rand.Reader)
    fmt.Printf("priv:%+v\n", priv)
}
//DecodePriv 解析私鑰文件生成私鑰,(RSA,和ECDSA兩種私鑰格式)
func DecodePriv(fileName, passwd string) (pubkey, priv interface{}, err error) {
    data, err := ioutil.ReadFile(fileName)
    if err != nil {
        return nil, nil, errors.New("讀取私鑰文件錯誤")
    }
    block, _ := pem.Decode(data)
    data, err = x509.DecryptPEMBlock(block, []byte(passwd))
    if err != nil {
        return nil, nil, err
    }
 
    privKey, err := x509.ParsePKCS1PrivateKey(data) //解析成RSA私鑰
    if err != nil {
        priv, err = x509.ParseECPrivateKey(data) //解析成ECDSA私鑰
        if err != nil {
            return nil, nil, errors.New("支持持RSA和ECDSA格式的私鑰")
        }
    }
    priv = privKey
    pubkey = &privKey.PublicKey
    return
}
//生成私鑰的pem文件
func encodePrivPemFile(fileName, passwd string, data []byte) error {
    block, err := x509.EncryptPEMBlock(rand.Reader, "RSA PRIVATE KEY", data, []byte(passwd), x509.PEMCipher3DES)
    if err != nil {
        return err
    }
    file, err := os.Create(fileName)
    if err != nil {
        return err
    }
    err = pem.Encode(file, block)
    if err != nil {
        return err
    }
    return nil
}

在這個代碼用有一些問題:使用ECDSA生成私鑰后加密的Type不知道填什么,暫時使用了”RSA PRIVATE KEY”。

和CertificateRequest有關的代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// EncodeCsr 生成證書請求
func EncodeCsr(country, organization, organizationlUnit, locality, province, streetAddress, postallCode []string, commonName, fileName string, priv interface{}) error {
    req := &x509.CertificateRequest{
        Subject: pkix.Name{
            Country:            country,
            Organization:       organization,
            OrganizationalUnit: organizationlUnit,
            Locality:           locality,
            Province:           province,
            StreetAddress:      streetAddress,
            PostalCode:         postallCode,
            CommonName:         commonName,
        },
    }
    data, err := x509.CreateCertificateRequest(rand.Reader, req, priv)
    if err != nil {
        return err
    }
    err = util.EncodePemFile(fileName, "CERTIFICATE REQUEST", data)
    return err
}
//DecodeCsr 解析CSRpem文件
func DecodeCsr(fileName string) (*x509.CertificateRequest, error) {
    data, err := util.DecodePemFile(fileName)
    if err != nil {
        return nil, err
    }
    req, err := x509.ParseCertificateRequest(data)
    return req, err
}

和生成Certificate有關的代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
//GenSignselfCertificate 生成自簽名證書
func GenSignselfCertificate(req *x509.CertificateRequest, publickey, privKey interface{}, fileName string, maxPath int, days time.Duration) error {
    template := &x509.Certificate{
        SerialNumber:          big.NewInt(random.Int63n(time.Now().Unix())),
        Subject:               req.Subject,
        NotBefore:             time.Now(),
        NotAfter:              time.Now().Add(days * 24 * time.Hour),
        BasicConstraintsValid: true,
        IsCA:               true,
        SignatureAlgorithm: x509.SHA1WithRSA, // 簽名算法選擇SHA1WithRSA
        KeyUsage:           x509.KeyUsageCertSign | x509.KeyUsageCRLSign | x509.KeyUsageDataEncipherment,
        SubjectKeyId:       []byte{1, 2, 3},
    }
    if maxPath > 0 { //如果長度超過0則設置了 最大的路徑長度
        template.MaxPathLen = maxPath
    }
    cert, err := x509.CreateCertificate(rand.Reader, template, template, publickey, privKey)
    if err != nil {
        return errors.New("簽發自簽名證書失敗")
    }
    err = util.EncodePemFile(fileName, "CERTIFICATE", cert)
    if err != nil {
        return err
    }
    return nil
}
//GenCertificate 生成非自簽名證書
func GenCertificate(req *x509.CertificateRequest, parentCert *x509.Certificate, pubKey, parentPrivKey interface{}, fileName string, isCA bool, days time.Duration) error {
    template := &x509.Certificate{
        SerialNumber: big.NewInt(random.Int63n(time.Now().Unix())),
        Subject:      req.Subject,
        NotBefore:    time.Now(),
        NotAfter:     time.Now().Add(days * 24 * time.Hour),
        // ExtKeyUsage: []x509.ExtKeyUsage{ //額外的使用
        //  x509.ExtKeyUsageClientAuth,
        //  x509.ExtKeyUsageServerAuth,
        // },
        //
 
        SignatureAlgorithm: x509.SHA1WithRSA,
    }
 
    if isCA {
        template.BasicConstraintsValid = true
        template.IsCA = true
    }
    cert, err := x509.CreateCertificate(rand.Reader, template, parentCert, pubKey, parentPrivKey)
    if err != nil {
        return errors.New("簽署證書失敗")
    }
    err = util.EncodePemFile(fileName, "CERTIFICATE", cert)
    if err != nil {
        return err
    }
    return nil
}

在生成證書這方法,由于可設置的內容過多,不應該使用參數來對證書內容進行控制。應該和openssl一樣使用配置文件的方式來對證書中的內容進行配置。

以上就是golang開發及數字證書研究分享的詳細內容,更多關于golang的資料請關注服務器之家其它相關文章!

原文鏈接:https://blog.csdn.net/ffzhihua/article/details/81975166

延伸 · 閱讀

精彩推薦
  • Golanggo日志系統logrus顯示文件和行號的操作

    go日志系統logrus顯示文件和行號的操作

    這篇文章主要介紹了go日志系統logrus顯示文件和行號的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧...

    SmallQinYan12302021-02-02
  • GolangGolang中Bit數組的實現方式

    Golang中Bit數組的實現方式

    這篇文章主要介紹了Golang中Bit數組的實現方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧...

    天易獨尊11682021-06-09
  • Golanggolang 通過ssh代理連接mysql的操作

    golang 通過ssh代理連接mysql的操作

    這篇文章主要介紹了golang 通過ssh代理連接mysql的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧...

    a165861639710342021-03-08
  • Golanggolang的httpserver優雅重啟方法詳解

    golang的httpserver優雅重啟方法詳解

    這篇文章主要給大家介紹了關于golang的httpserver優雅重啟的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,...

    helight2992020-05-14
  • GolangGolang通脈之數據類型詳情

    Golang通脈之數據類型詳情

    這篇文章主要介紹了Golang通脈之數據類型,在編程語言中標識符就是定義的具有某種意義的詞,比如變量名、常量名、函數名等等,Go語言中標識符允許由...

    4272021-11-24
  • Golanggolang如何使用struct的tag屬性的詳細介紹

    golang如何使用struct的tag屬性的詳細介紹

    這篇文章主要介紹了golang如何使用struct的tag屬性的詳細介紹,從例子說起,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看...

    Go語言中文網11352020-05-21
  • Golanggolang json.Marshal 特殊html字符被轉義的解決方法

    golang json.Marshal 特殊html字符被轉義的解決方法

    今天小編就為大家分享一篇golang json.Marshal 特殊html字符被轉義的解決方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧 ...

    李浩的life12792020-05-27
  • Golanggo語言制作端口掃描器

    go語言制作端口掃描器

    本文給大家分享的是使用go語言編寫的TCP端口掃描器,可以選擇IP范圍,掃描的端口,以及多線程,有需要的小伙伴可以參考下。 ...

    腳本之家3642020-04-25
主站蜘蛛池模板: 国产午夜精品一区二区三区免费 | 天天夜天天操 | 中文字幕一区二区三区四区 | 国产亚洲精品久久久闺蜜 | 国产一区成人 | 欧美1区2区在线观看 | 精品国产乱码一区二区 | 一级小毛片 | 国产精品18久久久久久久久 | 欧洲成人一区 | 蜜桃网站在线观看 | 视频在线91| 爱爱视频天天干 | 国产在线精品一区二区三区 | 九九热视频免费 | 国产欧美日韩在线不卡第一页 | 久久99国产精品视频 | 欧美wwwcom| 水卜樱一区二区av | 91短视频在线视频 | 国产一区二区三区网站 | 成人毛片一区 | cosplay裸体福利写真 | 中文字幕一区二区三区久久 | 欧美大荫蒂xxx| 国产高清自拍一区 | 久久久综| 欧美性生视频 | 91精品免费观看 | 国产精品成人免费一区久久羞羞 | 成人黄色在线视频 | 一级黄色性感片 | 国产成人av免费观看 | 欧美a在线看 | 精品xxxx户外露出视频 | 亚洲免费观看视频 | 欧美视频一区二区三区 | 国产成人精品午夜视频' | 午夜激情视频免费 | av免费在线观看国产 | 国产亚洲精品网站 |