mirror of
https://github.com/fatedier/frp.git
synced 2026-03-24 09:08:13 +08:00
using glide
This commit is contained in:
229
vendor/github.com/tjfoc/gmsm/sm2/cert_pool.go
generated
vendored
Normal file
229
vendor/github.com/tjfoc/gmsm/sm2/cert_pool.go
generated
vendored
Normal file
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
Copyright Suzhou Tongji Fintech Research Institute 2017 All Rights Reserved.
|
||||
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.
|
||||
*/
|
||||
|
||||
package sm2
|
||||
|
||||
import (
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"runtime"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Possible certificate files; stop after finding one.
|
||||
var certFiles = []string{
|
||||
"/etc/ssl/certs/ca-certificates.crt", // Debian/Ubuntu/Gentoo etc.
|
||||
"/etc/pki/tls/certs/ca-bundle.crt", // Fedora/RHEL 6
|
||||
"/etc/ssl/ca-bundle.pem", // OpenSUSE
|
||||
"/etc/pki/tls/cacert.pem", // OpenELEC
|
||||
"/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", // CentOS/RHEL 7
|
||||
}
|
||||
|
||||
// CertPool is a set of certificates.
|
||||
type CertPool struct {
|
||||
bySubjectKeyId map[string][]int
|
||||
byName map[string][]int
|
||||
certs []*Certificate
|
||||
}
|
||||
|
||||
// NewCertPool returns a new, empty CertPool.
|
||||
func NewCertPool() *CertPool {
|
||||
return &CertPool{
|
||||
bySubjectKeyId: make(map[string][]int),
|
||||
byName: make(map[string][]int),
|
||||
}
|
||||
}
|
||||
|
||||
// Possible directories with certificate files; stop after successfully
|
||||
// reading at least one file from a directory.
|
||||
var certDirectories = []string{
|
||||
"/etc/ssl/certs", // SLES10/SLES11, https://golang.org/issue/12139
|
||||
"/system/etc/security/cacerts", // Android
|
||||
}
|
||||
|
||||
var (
|
||||
once sync.Once
|
||||
systemRoots *CertPool
|
||||
systemRootsErr error
|
||||
)
|
||||
|
||||
func systemRootsPool() *CertPool {
|
||||
once.Do(initSystemRoots)
|
||||
return systemRoots
|
||||
}
|
||||
|
||||
func initSystemRoots() {
|
||||
systemRoots, systemRootsErr = loadSystemRoots()
|
||||
}
|
||||
|
||||
func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func loadSystemRoots() (*CertPool, error) {
|
||||
roots := NewCertPool()
|
||||
var firstErr error
|
||||
for _, file := range certFiles {
|
||||
data, err := ioutil.ReadFile(file)
|
||||
if err == nil {
|
||||
roots.AppendCertsFromPEM(data)
|
||||
return roots, nil
|
||||
}
|
||||
if firstErr == nil && !os.IsNotExist(err) {
|
||||
firstErr = err
|
||||
}
|
||||
}
|
||||
|
||||
for _, directory := range certDirectories {
|
||||
fis, err := ioutil.ReadDir(directory)
|
||||
if err != nil {
|
||||
if firstErr == nil && !os.IsNotExist(err) {
|
||||
firstErr = err
|
||||
}
|
||||
continue
|
||||
}
|
||||
rootsAdded := false
|
||||
for _, fi := range fis {
|
||||
data, err := ioutil.ReadFile(directory + "/" + fi.Name())
|
||||
if err == nil && roots.AppendCertsFromPEM(data) {
|
||||
rootsAdded = true
|
||||
}
|
||||
}
|
||||
if rootsAdded {
|
||||
return roots, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, firstErr
|
||||
}
|
||||
|
||||
// SystemCertPool returns a copy of the system cert pool.
|
||||
//
|
||||
// Any mutations to the returned pool are not written to disk and do
|
||||
// not affect any other pool.
|
||||
func SystemCertPool() (*CertPool, error) {
|
||||
if runtime.GOOS == "windows" {
|
||||
// Issue 16736, 18609:
|
||||
return nil, errors.New("crypto/x509: system root pool is not available on Windows")
|
||||
}
|
||||
|
||||
return loadSystemRoots()
|
||||
}
|
||||
|
||||
// findVerifiedParents attempts to find certificates in s which have signed the
|
||||
// given certificate. If any candidates were rejected then errCert will be set
|
||||
// to one of them, arbitrarily, and err will contain the reason that it was
|
||||
// rejected.
|
||||
func (s *CertPool) findVerifiedParents(cert *Certificate) (parents []int, errCert *Certificate, err error) {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
var candidates []int
|
||||
|
||||
if len(cert.AuthorityKeyId) > 0 {
|
||||
candidates = s.bySubjectKeyId[string(cert.AuthorityKeyId)]
|
||||
}
|
||||
if len(candidates) == 0 {
|
||||
candidates = s.byName[string(cert.RawIssuer)]
|
||||
}
|
||||
|
||||
for _, c := range candidates {
|
||||
if err = cert.CheckSignatureFrom(s.certs[c]); err == nil {
|
||||
parents = append(parents, c)
|
||||
} else {
|
||||
errCert = s.certs[c]
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (s *CertPool) contains(cert *Certificate) bool {
|
||||
if s == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
candidates := s.byName[string(cert.RawSubject)]
|
||||
for _, c := range candidates {
|
||||
if s.certs[c].Equal(cert) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// AddCert adds a certificate to a pool.
|
||||
func (s *CertPool) AddCert(cert *Certificate) {
|
||||
if cert == nil {
|
||||
panic("adding nil Certificate to CertPool")
|
||||
}
|
||||
|
||||
// Check that the certificate isn't being added twice.
|
||||
if s.contains(cert) {
|
||||
return
|
||||
}
|
||||
|
||||
n := len(s.certs)
|
||||
s.certs = append(s.certs, cert)
|
||||
|
||||
if len(cert.SubjectKeyId) > 0 {
|
||||
keyId := string(cert.SubjectKeyId)
|
||||
s.bySubjectKeyId[keyId] = append(s.bySubjectKeyId[keyId], n)
|
||||
}
|
||||
name := string(cert.RawSubject)
|
||||
s.byName[name] = append(s.byName[name], n)
|
||||
}
|
||||
|
||||
// AppendCertsFromPEM attempts to parse a series of PEM encoded certificates.
|
||||
// It appends any certificates found to s and reports whether any certificates
|
||||
// were successfully parsed.
|
||||
//
|
||||
// On many Linux systems, /etc/ssl/cert.pem will contain the system wide set
|
||||
// of root CAs in a format suitable for this function.
|
||||
func (s *CertPool) AppendCertsFromPEM(pemCerts []byte) (ok bool) {
|
||||
for len(pemCerts) > 0 {
|
||||
var block *pem.Block
|
||||
block, pemCerts = pem.Decode(pemCerts)
|
||||
if block == nil {
|
||||
break
|
||||
}
|
||||
if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
cert, err := ParseCertificate(block.Bytes)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
s.AddCert(cert)
|
||||
ok = true
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Subjects returns a list of the DER-encoded subjects of
|
||||
// all of the certificates in the pool.
|
||||
func (s *CertPool) Subjects() [][]byte {
|
||||
res := make([][]byte, len(s.certs))
|
||||
for i, c := range s.certs {
|
||||
res[i] = c.RawSubject
|
||||
}
|
||||
return res
|
||||
}
|
||||
43
vendor/github.com/tjfoc/gmsm/sm2/p256.go
generated
vendored
Normal file
43
vendor/github.com/tjfoc/gmsm/sm2/p256.go
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
Copyright Suzhou Tongji Fintech Research Institute 2017 All Rights Reserved.
|
||||
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.
|
||||
*/
|
||||
|
||||
package sm2
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
"math/big"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var initonce sync.Once
|
||||
var p256Sm2Params *elliptic.CurveParams
|
||||
|
||||
// 取自elliptic的p256.go文件,修改曲线参数为sm2
|
||||
// See FIPS 186-3, section D.2.3
|
||||
func initP256Sm2() {
|
||||
p256Sm2Params = &elliptic.CurveParams{Name: "SM2-P-256"} // 注明为SM2
|
||||
//SM2椭 椭 圆 曲 线 公 钥 密 码 算 法 推 荐 曲 线 参 数
|
||||
p256Sm2Params.P, _ = new(big.Int).SetString("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF", 16)
|
||||
p256Sm2Params.N, _ = new(big.Int).SetString("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", 16)
|
||||
p256Sm2Params.B, _ = new(big.Int).SetString("28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93", 16)
|
||||
p256Sm2Params.Gx, _ = new(big.Int).SetString("32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", 16)
|
||||
p256Sm2Params.Gy, _ = new(big.Int).SetString("BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", 16)
|
||||
p256Sm2Params.BitSize = 256
|
||||
}
|
||||
|
||||
func P256Sm2() elliptic.Curve {
|
||||
initonce.Do(initP256Sm2)
|
||||
return p256Sm2Params
|
||||
}
|
||||
132
vendor/github.com/tjfoc/gmsm/sm2/pkcs1.go
generated
vendored
Normal file
132
vendor/github.com/tjfoc/gmsm/sm2/pkcs1.go
generated
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
Copyright Suzhou Tongji Fintech Research Institute 2017 All Rights Reserved.
|
||||
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.
|
||||
*/
|
||||
|
||||
package sm2
|
||||
|
||||
import (
|
||||
"crypto/rsa"
|
||||
"encoding/asn1"
|
||||
"errors"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
// pkcs1PrivateKey is a structure which mirrors the PKCS#1 ASN.1 for an RSA private key.
|
||||
type pkcs1PrivateKey struct {
|
||||
Version int
|
||||
N *big.Int
|
||||
E int
|
||||
D *big.Int
|
||||
P *big.Int
|
||||
Q *big.Int
|
||||
// We ignore these values, if present, because rsa will calculate them.
|
||||
Dp *big.Int `asn1:"optional"`
|
||||
Dq *big.Int `asn1:"optional"`
|
||||
Qinv *big.Int `asn1:"optional"`
|
||||
|
||||
AdditionalPrimes []pkcs1AdditionalRSAPrime `asn1:"optional,omitempty"`
|
||||
}
|
||||
|
||||
type pkcs1AdditionalRSAPrime struct {
|
||||
Prime *big.Int
|
||||
|
||||
// We ignore these values because rsa will calculate them.
|
||||
Exp *big.Int
|
||||
Coeff *big.Int
|
||||
}
|
||||
|
||||
// ParsePKCS1PrivateKey returns an RSA private key from its ASN.1 PKCS#1 DER encoded form.
|
||||
func ParsePKCS1PrivateKey(der []byte) (*rsa.PrivateKey, error) {
|
||||
var priv pkcs1PrivateKey
|
||||
rest, err := asn1.Unmarshal(der, &priv)
|
||||
if len(rest) > 0 {
|
||||
return nil, asn1.SyntaxError{Msg: "trailing data"}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if priv.Version > 1 {
|
||||
return nil, errors.New("x509: unsupported private key version")
|
||||
}
|
||||
|
||||
if priv.N.Sign() <= 0 || priv.D.Sign() <= 0 || priv.P.Sign() <= 0 || priv.Q.Sign() <= 0 {
|
||||
return nil, errors.New("x509: private key contains zero or negative value")
|
||||
}
|
||||
|
||||
key := new(rsa.PrivateKey)
|
||||
key.PublicKey = rsa.PublicKey{
|
||||
E: priv.E,
|
||||
N: priv.N,
|
||||
}
|
||||
|
||||
key.D = priv.D
|
||||
key.Primes = make([]*big.Int, 2+len(priv.AdditionalPrimes))
|
||||
key.Primes[0] = priv.P
|
||||
key.Primes[1] = priv.Q
|
||||
for i, a := range priv.AdditionalPrimes {
|
||||
if a.Prime.Sign() <= 0 {
|
||||
return nil, errors.New("x509: private key contains zero or negative prime")
|
||||
}
|
||||
key.Primes[i+2] = a.Prime
|
||||
// We ignore the other two values because rsa will calculate
|
||||
// them as needed.
|
||||
}
|
||||
|
||||
err = key.Validate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
key.Precompute()
|
||||
|
||||
return key, nil
|
||||
}
|
||||
|
||||
// MarshalPKCS1PrivateKey converts a private key to ASN.1 DER encoded form.
|
||||
func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte {
|
||||
key.Precompute()
|
||||
|
||||
version := 0
|
||||
if len(key.Primes) > 2 {
|
||||
version = 1
|
||||
}
|
||||
|
||||
priv := pkcs1PrivateKey{
|
||||
Version: version,
|
||||
N: key.N,
|
||||
E: key.PublicKey.E,
|
||||
D: key.D,
|
||||
P: key.Primes[0],
|
||||
Q: key.Primes[1],
|
||||
Dp: key.Precomputed.Dp,
|
||||
Dq: key.Precomputed.Dq,
|
||||
Qinv: key.Precomputed.Qinv,
|
||||
}
|
||||
|
||||
priv.AdditionalPrimes = make([]pkcs1AdditionalRSAPrime, len(key.Precomputed.CRTValues))
|
||||
for i, values := range key.Precomputed.CRTValues {
|
||||
priv.AdditionalPrimes[i].Prime = key.Primes[2+i]
|
||||
priv.AdditionalPrimes[i].Exp = values.Exp
|
||||
priv.AdditionalPrimes[i].Coeff = values.Coeff
|
||||
}
|
||||
|
||||
b, _ := asn1.Marshal(priv)
|
||||
return b
|
||||
}
|
||||
|
||||
// rsaPublicKey reflects the ASN.1 structure of a PKCS#1 public key.
|
||||
type rsaPublicKey struct {
|
||||
N *big.Int
|
||||
E int
|
||||
}
|
||||
488
vendor/github.com/tjfoc/gmsm/sm2/pkcs8.go
generated
vendored
Normal file
488
vendor/github.com/tjfoc/gmsm/sm2/pkcs8.go
generated
vendored
Normal file
@@ -0,0 +1,488 @@
|
||||
/*
|
||||
Copyright Suzhou Tongji Fintech Research Institute 2017 All Rights Reserved.
|
||||
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.
|
||||
*/
|
||||
|
||||
package sm2
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/elliptic"
|
||||
"crypto/hmac"
|
||||
"crypto/md5"
|
||||
"crypto/rand"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"hash"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"os"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
/*
|
||||
* reference to RFC5959 and RFC2898
|
||||
*/
|
||||
|
||||
var (
|
||||
oidPBES1 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 5, 3} // pbeWithMD5AndDES-CBC(PBES1)
|
||||
oidPBES2 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 5, 13} // id-PBES2(PBES2)
|
||||
oidPBKDF2 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 5, 12} // id-PBKDF2
|
||||
|
||||
oidKEYMD5 = asn1.ObjectIdentifier{1, 2, 840, 113549, 2, 5}
|
||||
oidKEYSHA1 = asn1.ObjectIdentifier{1, 2, 840, 113549, 2, 7}
|
||||
oidKEYSHA256 = asn1.ObjectIdentifier{1, 2, 840, 113549, 2, 9}
|
||||
oidKEYSHA512 = asn1.ObjectIdentifier{1, 2, 840, 113549, 2, 11}
|
||||
|
||||
oidAES128CBC = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 2}
|
||||
oidAES256CBC = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 42}
|
||||
|
||||
oidSM2 = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1}
|
||||
)
|
||||
|
||||
// reference to https://www.rfc-editor.org/rfc/rfc5958.txt
|
||||
type PrivateKeyInfo struct {
|
||||
Version int // v1 or v2
|
||||
PrivateKeyAlgorithm []asn1.ObjectIdentifier
|
||||
PrivateKey []byte
|
||||
}
|
||||
|
||||
// reference to https://www.rfc-editor.org/rfc/rfc5958.txt
|
||||
type EncryptedPrivateKeyInfo struct {
|
||||
EncryptionAlgorithm Pbes2Algorithms
|
||||
EncryptedData []byte
|
||||
}
|
||||
|
||||
// reference to https://www.ietf.org/rfc/rfc2898.txt
|
||||
type Pbes2Algorithms struct {
|
||||
IdPBES2 asn1.ObjectIdentifier
|
||||
Pbes2Params Pbes2Params
|
||||
}
|
||||
|
||||
// reference to https://www.ietf.org/rfc/rfc2898.txt
|
||||
type Pbes2Params struct {
|
||||
KeyDerivationFunc Pbes2KDfs // PBES2-KDFs
|
||||
EncryptionScheme Pbes2Encs // PBES2-Encs
|
||||
}
|
||||
|
||||
// reference to https://www.ietf.org/rfc/rfc2898.txt
|
||||
type Pbes2KDfs struct {
|
||||
IdPBKDF2 asn1.ObjectIdentifier
|
||||
Pkdf2Params Pkdf2Params
|
||||
}
|
||||
|
||||
type Pbes2Encs struct {
|
||||
EncryAlgo asn1.ObjectIdentifier
|
||||
IV []byte
|
||||
}
|
||||
|
||||
// reference to https://www.ietf.org/rfc/rfc2898.txt
|
||||
type Pkdf2Params struct {
|
||||
Salt []byte
|
||||
IterationCount int
|
||||
Prf pkix.AlgorithmIdentifier
|
||||
}
|
||||
|
||||
type sm2PrivateKey struct {
|
||||
Version int
|
||||
PrivateKey []byte
|
||||
NamedCurveOID asn1.ObjectIdentifier `asn1:"optional,explicit,tag:0"`
|
||||
PublicKey asn1.BitString `asn1:"optional,explicit,tag:1"`
|
||||
}
|
||||
|
||||
type pkcs8 struct {
|
||||
Version int
|
||||
Algo pkix.AlgorithmIdentifier
|
||||
PrivateKey []byte
|
||||
}
|
||||
|
||||
// copy from crypto/pbkdf2.go
|
||||
func pbkdf(password, salt []byte, iter, keyLen int, h func() hash.Hash) []byte {
|
||||
prf := hmac.New(h, password)
|
||||
hashLen := prf.Size()
|
||||
numBlocks := (keyLen + hashLen - 1) / hashLen
|
||||
|
||||
var buf [4]byte
|
||||
dk := make([]byte, 0, numBlocks*hashLen)
|
||||
U := make([]byte, hashLen)
|
||||
for block := 1; block <= numBlocks; block++ {
|
||||
// N.B.: || means concatenation, ^ means XOR
|
||||
// for each block T_i = U_1 ^ U_2 ^ ... ^ U_iter
|
||||
// U_1 = PRF(password, salt || uint(i))
|
||||
prf.Reset()
|
||||
prf.Write(salt)
|
||||
buf[0] = byte(block >> 24)
|
||||
buf[1] = byte(block >> 16)
|
||||
buf[2] = byte(block >> 8)
|
||||
buf[3] = byte(block)
|
||||
prf.Write(buf[:4])
|
||||
dk = prf.Sum(dk)
|
||||
T := dk[len(dk)-hashLen:]
|
||||
copy(U, T)
|
||||
|
||||
// U_n = PRF(password, U_(n-1))
|
||||
for n := 2; n <= iter; n++ {
|
||||
prf.Reset()
|
||||
prf.Write(U)
|
||||
U = U[:0]
|
||||
U = prf.Sum(U)
|
||||
for x := range U {
|
||||
T[x] ^= U[x]
|
||||
}
|
||||
}
|
||||
}
|
||||
return dk[:keyLen]
|
||||
}
|
||||
|
||||
func ParseSm2PublicKey(der []byte) (*PublicKey, error) {
|
||||
var pubkey pkixPublicKey
|
||||
|
||||
if _, err := asn1.Unmarshal(der, &pubkey); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !reflect.DeepEqual(pubkey.Algo.Algorithm, oidSM2) {
|
||||
return nil, errors.New("x509: not sm2 elliptic curve")
|
||||
}
|
||||
curve := P256Sm2()
|
||||
x, y := elliptic.Unmarshal(curve, pubkey.BitString.Bytes)
|
||||
pub := PublicKey{
|
||||
Curve: curve,
|
||||
X: x,
|
||||
Y: y,
|
||||
}
|
||||
return &pub, nil
|
||||
}
|
||||
|
||||
func MarshalSm2PublicKey(key *PublicKey) ([]byte, error) {
|
||||
var r pkixPublicKey
|
||||
var algo pkix.AlgorithmIdentifier
|
||||
|
||||
algo.Algorithm = oidSM2
|
||||
algo.Parameters.Class = 0
|
||||
algo.Parameters.Tag = 6
|
||||
algo.Parameters.IsCompound = false
|
||||
algo.Parameters.FullBytes = []byte{6, 8, 42, 129, 28, 207, 85, 1, 130, 45} // asn1.Marshal(asn1.ObjectIdentifier{1, 2, 156, 10197, 1, 301})
|
||||
r.Algo = algo
|
||||
r.BitString = asn1.BitString{Bytes: elliptic.Marshal(key.Curve, key.X, key.Y)}
|
||||
return asn1.Marshal(r)
|
||||
}
|
||||
|
||||
func ParseSm2PrivateKey(der []byte) (*PrivateKey, error) {
|
||||
var privKey sm2PrivateKey
|
||||
|
||||
if _, err := asn1.Unmarshal(der, &privKey); err != nil {
|
||||
return nil, errors.New("x509: failed to parse SM2 private key: " + err.Error())
|
||||
}
|
||||
curve := P256Sm2()
|
||||
k := new(big.Int).SetBytes(privKey.PrivateKey)
|
||||
curveOrder := curve.Params().N
|
||||
if k.Cmp(curveOrder) >= 0 {
|
||||
return nil, errors.New("x509: invalid elliptic curve private key value")
|
||||
}
|
||||
priv := new(PrivateKey)
|
||||
priv.Curve = curve
|
||||
priv.D = k
|
||||
privateKey := make([]byte, (curveOrder.BitLen()+7)/8)
|
||||
for len(privKey.PrivateKey) > len(privateKey) {
|
||||
if privKey.PrivateKey[0] != 0 {
|
||||
return nil, errors.New("x509: invalid private key length")
|
||||
}
|
||||
privKey.PrivateKey = privKey.PrivateKey[1:]
|
||||
}
|
||||
copy(privateKey[len(privateKey)-len(privKey.PrivateKey):], privKey.PrivateKey)
|
||||
priv.X, priv.Y = curve.ScalarBaseMult(privateKey)
|
||||
return priv, nil
|
||||
}
|
||||
|
||||
func ParsePKCS8UnecryptedPrivateKey(der []byte) (*PrivateKey, error) {
|
||||
var privKey pkcs8
|
||||
|
||||
if _, err := asn1.Unmarshal(der, &privKey); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !reflect.DeepEqual(privKey.Algo.Algorithm, oidSM2) {
|
||||
return nil, errors.New("x509: not sm2 elliptic curve")
|
||||
}
|
||||
return ParseSm2PrivateKey(privKey.PrivateKey)
|
||||
}
|
||||
|
||||
func ParsePKCS8EcryptedPrivateKey(der, pwd []byte) (*PrivateKey, error) {
|
||||
var keyInfo EncryptedPrivateKeyInfo
|
||||
|
||||
_, err := asn1.Unmarshal(der, &keyInfo)
|
||||
if err != nil {
|
||||
return nil, errors.New("x509: unknown format")
|
||||
}
|
||||
if !reflect.DeepEqual(keyInfo.EncryptionAlgorithm.IdPBES2, oidPBES2) {
|
||||
return nil, errors.New("x509: only support PBES2")
|
||||
}
|
||||
encryptionScheme := keyInfo.EncryptionAlgorithm.Pbes2Params.EncryptionScheme
|
||||
keyDerivationFunc := keyInfo.EncryptionAlgorithm.Pbes2Params.KeyDerivationFunc
|
||||
if !reflect.DeepEqual(keyDerivationFunc.IdPBKDF2, oidPBKDF2) {
|
||||
return nil, errors.New("x509: only support PBKDF2")
|
||||
}
|
||||
pkdf2Params := keyDerivationFunc.Pkdf2Params
|
||||
if !reflect.DeepEqual(encryptionScheme.EncryAlgo, oidAES128CBC) &&
|
||||
!reflect.DeepEqual(encryptionScheme.EncryAlgo, oidAES256CBC) {
|
||||
return nil, errors.New("x509: unknow encryption algorithm")
|
||||
}
|
||||
iv := encryptionScheme.IV
|
||||
salt := pkdf2Params.Salt
|
||||
iter := pkdf2Params.IterationCount
|
||||
encryptedKey := keyInfo.EncryptedData
|
||||
var key []byte
|
||||
switch {
|
||||
case pkdf2Params.Prf.Algorithm.Equal(oidKEYMD5):
|
||||
key = pbkdf(pwd, salt, iter, 32, md5.New)
|
||||
break
|
||||
case pkdf2Params.Prf.Algorithm.Equal(oidKEYSHA1):
|
||||
key = pbkdf(pwd, salt, iter, 32, sha1.New)
|
||||
break
|
||||
case pkdf2Params.Prf.Algorithm.Equal(oidKEYSHA256):
|
||||
key = pbkdf(pwd, salt, iter, 32, sha256.New)
|
||||
break
|
||||
case pkdf2Params.Prf.Algorithm.Equal(oidKEYSHA512):
|
||||
key = pbkdf(pwd, salt, iter, 32, sha512.New)
|
||||
break
|
||||
default:
|
||||
return nil, errors.New("x509: unknown hash algorithm")
|
||||
}
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mode := cipher.NewCBCDecrypter(block, iv)
|
||||
mode.CryptBlocks(encryptedKey, encryptedKey)
|
||||
rKey, err := ParsePKCS8UnecryptedPrivateKey(encryptedKey)
|
||||
if err != nil {
|
||||
return nil, errors.New("pkcs8: incorrect password")
|
||||
}
|
||||
return rKey, nil
|
||||
}
|
||||
|
||||
func ParsePKCS8PrivateKey(der, pwd []byte) (*PrivateKey, error) {
|
||||
if pwd == nil {
|
||||
return ParsePKCS8UnecryptedPrivateKey(der)
|
||||
}
|
||||
return ParsePKCS8EcryptedPrivateKey(der, pwd)
|
||||
}
|
||||
|
||||
func MarshalSm2UnecryptedPrivateKey(key *PrivateKey) ([]byte, error) {
|
||||
var r pkcs8
|
||||
var priv sm2PrivateKey
|
||||
var algo pkix.AlgorithmIdentifier
|
||||
|
||||
algo.Algorithm = oidSM2
|
||||
algo.Parameters.Class = 0
|
||||
algo.Parameters.Tag = 6
|
||||
algo.Parameters.IsCompound = false
|
||||
algo.Parameters.FullBytes = []byte{6, 8, 42, 129, 28, 207, 85, 1, 130, 45} // asn1.Marshal(asn1.ObjectIdentifier{1, 2, 156, 10197, 1, 301})
|
||||
priv.Version = 1
|
||||
priv.NamedCurveOID = oidNamedCurveP256SM2
|
||||
priv.PublicKey = asn1.BitString{Bytes: elliptic.Marshal(key.Curve, key.X, key.Y)}
|
||||
priv.PrivateKey = key.D.Bytes()
|
||||
r.Version = 0
|
||||
r.Algo = algo
|
||||
r.PrivateKey, _ = asn1.Marshal(priv)
|
||||
return asn1.Marshal(r)
|
||||
}
|
||||
|
||||
func MarshalSm2EcryptedPrivateKey(PrivKey *PrivateKey, pwd []byte) ([]byte, error) {
|
||||
der, err := MarshalSm2UnecryptedPrivateKey(PrivKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iter := 2048
|
||||
salt := make([]byte, 8)
|
||||
iv := make([]byte, 16)
|
||||
rand.Reader.Read(salt)
|
||||
rand.Reader.Read(iv)
|
||||
key := pbkdf(pwd, salt, iter, 32, sha1.New) // 默认是SHA1
|
||||
padding := aes.BlockSize - len(der)%aes.BlockSize
|
||||
if padding > 0 {
|
||||
n := len(der)
|
||||
der = append(der, make([]byte, padding)...)
|
||||
for i := 0; i < padding; i++ {
|
||||
der[n+i] = byte(padding)
|
||||
}
|
||||
}
|
||||
encryptedKey := make([]byte, len(der))
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mode := cipher.NewCBCEncrypter(block, iv)
|
||||
mode.CryptBlocks(encryptedKey, der)
|
||||
var algorithmIdentifier pkix.AlgorithmIdentifier
|
||||
algorithmIdentifier.Algorithm = oidKEYSHA1
|
||||
algorithmIdentifier.Parameters.Tag = 5
|
||||
algorithmIdentifier.Parameters.IsCompound = false
|
||||
algorithmIdentifier.Parameters.FullBytes = []byte{5, 0}
|
||||
keyDerivationFunc := Pbes2KDfs{
|
||||
oidPBKDF2,
|
||||
Pkdf2Params{
|
||||
salt,
|
||||
iter,
|
||||
algorithmIdentifier,
|
||||
},
|
||||
}
|
||||
encryptionScheme := Pbes2Encs{
|
||||
oidAES256CBC,
|
||||
iv,
|
||||
}
|
||||
pbes2Algorithms := Pbes2Algorithms{
|
||||
oidPBES2,
|
||||
Pbes2Params{
|
||||
keyDerivationFunc,
|
||||
encryptionScheme,
|
||||
},
|
||||
}
|
||||
encryptedPkey := EncryptedPrivateKeyInfo{
|
||||
pbes2Algorithms,
|
||||
encryptedKey,
|
||||
}
|
||||
return asn1.Marshal(encryptedPkey)
|
||||
}
|
||||
|
||||
func MarshalSm2PrivateKey(key *PrivateKey, pwd []byte) ([]byte, error) {
|
||||
if pwd == nil {
|
||||
return MarshalSm2UnecryptedPrivateKey(key)
|
||||
}
|
||||
return MarshalSm2EcryptedPrivateKey(key, pwd)
|
||||
}
|
||||
|
||||
func ReadPrivateKeyFromMem(data []byte, pwd []byte) (*PrivateKey, error) {
|
||||
var block *pem.Block
|
||||
|
||||
block, _ = pem.Decode(data)
|
||||
if block == nil {
|
||||
return nil, errors.New("failed to decode private key")
|
||||
}
|
||||
priv, err := ParsePKCS8PrivateKey(block.Bytes, pwd)
|
||||
return priv, err
|
||||
}
|
||||
|
||||
func ReadPrivateKeyFromPem(FileName string, pwd []byte) (*PrivateKey, error) {
|
||||
data, err := ioutil.ReadFile(FileName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ReadPrivateKeyFromMem(data, pwd)
|
||||
}
|
||||
|
||||
func WritePrivateKeytoMem(key *PrivateKey, pwd []byte) ([]byte, error) {
|
||||
var block *pem.Block
|
||||
|
||||
der, err := MarshalSm2PrivateKey(key, pwd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if pwd != nil {
|
||||
block = &pem.Block{
|
||||
Type: "ENCRYPTED PRIVATE KEY",
|
||||
Bytes: der,
|
||||
}
|
||||
} else {
|
||||
block = &pem.Block{
|
||||
Type: "PRIVATE KEY",
|
||||
Bytes: der,
|
||||
}
|
||||
}
|
||||
return pem.EncodeToMemory(block), nil
|
||||
}
|
||||
|
||||
func WritePrivateKeytoPem(FileName string, key *PrivateKey, pwd []byte) (bool, error) {
|
||||
var block *pem.Block
|
||||
|
||||
der, err := MarshalSm2PrivateKey(key, pwd)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if pwd != nil {
|
||||
block = &pem.Block{
|
||||
Type: "ENCRYPTED PRIVATE KEY",
|
||||
Bytes: der,
|
||||
}
|
||||
} else {
|
||||
block = &pem.Block{
|
||||
Type: "PRIVATE KEY",
|
||||
Bytes: der,
|
||||
}
|
||||
}
|
||||
file, err := os.Create(FileName)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer file.Close()
|
||||
err = pem.Encode(file, block)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func ReadPublicKeyFromMem(data []byte, _ []byte) (*PublicKey, error) {
|
||||
block, _ := pem.Decode(data)
|
||||
if block == nil || block.Type != "PUBLIC KEY" {
|
||||
return nil, errors.New("failed to decode public key")
|
||||
}
|
||||
pub, err := ParseSm2PublicKey(block.Bytes)
|
||||
return pub, err
|
||||
}
|
||||
|
||||
func ReadPublicKeyFromPem(FileName string, pwd []byte) (*PublicKey, error) {
|
||||
data, err := ioutil.ReadFile(FileName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ReadPublicKeyFromMem(data, pwd)
|
||||
}
|
||||
|
||||
func WritePublicKeytoMem(key *PublicKey, _ []byte) ([]byte, error) {
|
||||
der, err := MarshalSm2PublicKey(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
block := &pem.Block{
|
||||
Type: "PUBLIC KEY",
|
||||
Bytes: der,
|
||||
}
|
||||
return pem.EncodeToMemory(block), nil
|
||||
}
|
||||
|
||||
func WritePublicKeytoPem(FileName string, key *PublicKey, _ []byte) (bool, error) {
|
||||
der, err := MarshalSm2PublicKey(key)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
block := &pem.Block{
|
||||
Type: "PUBLIC KEY",
|
||||
Bytes: der,
|
||||
}
|
||||
file, err := os.Create(FileName)
|
||||
defer file.Close()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
err = pem.Encode(file, block)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
222
vendor/github.com/tjfoc/gmsm/sm2/sm2.go
generated
vendored
Normal file
222
vendor/github.com/tjfoc/gmsm/sm2/sm2.go
generated
vendored
Normal file
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
Copyright Suzhou Tongji Fintech Research Institute 2017 All Rights Reserved.
|
||||
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.
|
||||
*/
|
||||
|
||||
package sm2
|
||||
|
||||
// reference to ecdsa
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/sha512"
|
||||
"encoding/asn1"
|
||||
"errors"
|
||||
"io"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
type combinedMult interface {
|
||||
CombinedMult(bigX, bigY *big.Int, baseScalar, scalar []byte) (x, y *big.Int)
|
||||
}
|
||||
|
||||
const (
|
||||
aesIV = "IV for <SM2> CTR"
|
||||
)
|
||||
|
||||
type PublicKey struct {
|
||||
elliptic.Curve
|
||||
X, Y *big.Int
|
||||
}
|
||||
|
||||
type PrivateKey struct {
|
||||
PublicKey
|
||||
D *big.Int
|
||||
}
|
||||
|
||||
type sm2Signature struct {
|
||||
R, S *big.Int
|
||||
}
|
||||
|
||||
// The SM2's private key contains the public key
|
||||
func (priv *PrivateKey) Public() crypto.PublicKey {
|
||||
return &priv.PublicKey
|
||||
}
|
||||
|
||||
// sign format = 30 + len(z) + 02 + len(r) + r + 02 + len(s) + s, z being what follows its size, ie 02+len(r)+r+02+len(s)+s
|
||||
func (priv *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ([]byte, error) {
|
||||
r, s, err := Sign(priv, msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return asn1.Marshal(sm2Signature{r, s})
|
||||
}
|
||||
|
||||
func (pub *PublicKey) Verify(msg []byte, sign []byte) bool {
|
||||
var sm2Sign sm2Signature
|
||||
_, err := asn1.Unmarshal(sign, &sm2Sign)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return Verify(pub, msg, sm2Sign.R, sm2Sign.S)
|
||||
}
|
||||
|
||||
var one = new(big.Int).SetInt64(1)
|
||||
|
||||
func randFieldElement(c elliptic.Curve, rand io.Reader) (k *big.Int, err error) {
|
||||
params := c.Params()
|
||||
b := make([]byte, params.BitSize/8+8)
|
||||
_, err = io.ReadFull(rand, b)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
k = new(big.Int).SetBytes(b)
|
||||
n := new(big.Int).Sub(params.N, one)
|
||||
k.Mod(k, n)
|
||||
k.Add(k, one)
|
||||
return
|
||||
}
|
||||
|
||||
func GenerateKey() (*PrivateKey, error) {
|
||||
c := P256Sm2()
|
||||
k, err := randFieldElement(c, rand.Reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
priv := new(PrivateKey)
|
||||
priv.PublicKey.Curve = c
|
||||
priv.D = k
|
||||
priv.PublicKey.X, priv.PublicKey.Y = c.ScalarBaseMult(k.Bytes())
|
||||
return priv, nil
|
||||
}
|
||||
|
||||
var errZeroParam = errors.New("zero parameter")
|
||||
|
||||
func Sign(priv *PrivateKey, hash []byte) (r, s *big.Int, err error) {
|
||||
entropylen := (priv.Curve.Params().BitSize + 7) / 16
|
||||
if entropylen > 32 {
|
||||
entropylen = 32
|
||||
}
|
||||
entropy := make([]byte, entropylen)
|
||||
_, err = io.ReadFull(rand.Reader, entropy)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Initialize an SHA-512 hash context; digest ...
|
||||
md := sha512.New()
|
||||
md.Write(priv.D.Bytes()) // the private key,
|
||||
md.Write(entropy) // the entropy,
|
||||
md.Write(hash) // and the input hash;
|
||||
key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512),
|
||||
// which is an indifferentiable MAC.
|
||||
|
||||
// Create an AES-CTR instance to use as a CSPRNG.
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Create a CSPRNG that xors a stream of zeros with
|
||||
// the output of the AES-CTR instance.
|
||||
csprng := cipher.StreamReader{
|
||||
R: zeroReader,
|
||||
S: cipher.NewCTR(block, []byte(aesIV)),
|
||||
}
|
||||
|
||||
// See [NSA] 3.4.1
|
||||
c := priv.PublicKey.Curve
|
||||
N := c.Params().N
|
||||
if N.Sign() == 0 {
|
||||
return nil, nil, errZeroParam
|
||||
}
|
||||
var k *big.Int
|
||||
e := new(big.Int).SetBytes(hash)
|
||||
for { // 调整算法细节以实现SM2
|
||||
for {
|
||||
k, err = randFieldElement(c, csprng)
|
||||
if err != nil {
|
||||
r = nil
|
||||
return
|
||||
}
|
||||
r, _ = priv.Curve.ScalarBaseMult(k.Bytes())
|
||||
r.Add(r, e)
|
||||
r.Mod(r, N)
|
||||
if r.Sign() != 0 {
|
||||
break
|
||||
}
|
||||
if t := new(big.Int).Add(r, k); t.Cmp(N) == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
rD := new(big.Int).Mul(priv.D, r)
|
||||
s = new(big.Int).Sub(k, rD)
|
||||
d1 := new(big.Int).Add(priv.D, one)
|
||||
d1Inv := new(big.Int).ModInverse(d1, N)
|
||||
s.Mul(s, d1Inv)
|
||||
s.Mod(s, N)
|
||||
if s.Sign() != 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
|
||||
c := pub.Curve
|
||||
N := c.Params().N
|
||||
|
||||
if r.Sign() <= 0 || s.Sign() <= 0 {
|
||||
return false
|
||||
}
|
||||
if r.Cmp(N) >= 0 || s.Cmp(N) >= 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
// 调整算法细节以实现SM2
|
||||
t := new(big.Int).Add(r, s)
|
||||
t.Mod(t, N)
|
||||
if N.Sign() == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
var x *big.Int
|
||||
if opt, ok := c.(combinedMult); ok {
|
||||
x, _ = opt.CombinedMult(pub.X, pub.Y, s.Bytes(), t.Bytes())
|
||||
} else {
|
||||
x1, y1 := c.ScalarBaseMult(s.Bytes())
|
||||
x2, y2 := c.ScalarMult(pub.X, pub.Y, t.Bytes())
|
||||
x, _ = c.Add(x1, y1, x2, y2)
|
||||
}
|
||||
|
||||
e := new(big.Int).SetBytes(hash)
|
||||
x.Add(x, e)
|
||||
x.Mod(x, N)
|
||||
return x.Cmp(r) == 0
|
||||
}
|
||||
|
||||
type zr struct {
|
||||
io.Reader
|
||||
}
|
||||
|
||||
func (z *zr) Read(dst []byte) (n int, err error) {
|
||||
for i := range dst {
|
||||
dst[i] = 0
|
||||
}
|
||||
return len(dst), nil
|
||||
}
|
||||
|
||||
var zeroReader = &zr{}
|
||||
184
vendor/github.com/tjfoc/gmsm/sm2/sm2_test.go
generated
vendored
Normal file
184
vendor/github.com/tjfoc/gmsm/sm2/sm2_test.go
generated
vendored
Normal file
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
Copyright Suzhou Tongji Fintech Research Institute 2017 All Rights Reserved.
|
||||
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.
|
||||
*/
|
||||
|
||||
package sm2
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"math/big"
|
||||
"net"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestSm2(t *testing.T) {
|
||||
priv, err := GenerateKey() // 生成密钥对
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
ok, err := WritePrivateKeytoPem("priv.pem", priv, nil) // 生成密钥文件
|
||||
if ok != true {
|
||||
log.Fatal(err)
|
||||
}
|
||||
pubKey, _ := priv.Public().(*PublicKey)
|
||||
ok, err = WritePublicKeytoPem("pub.pem", pubKey, nil) // 生成公钥文件
|
||||
if ok != true {
|
||||
log.Fatal(err)
|
||||
}
|
||||
msg := []byte("test")
|
||||
err = ioutil.WriteFile("ifile", msg, os.FileMode(0644)) // 生成测试文件
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
privKey, err := ReadPrivateKeyFromPem("priv.pem", nil) // 读取密钥
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
pubKey, err = ReadPublicKeyFromPem("pub.pem", nil) // 读取公钥
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
msg, _ = ioutil.ReadFile("ifile") // 从文件读取数据
|
||||
sign, err := privKey.Sign(rand.Reader, msg, nil) // 签名
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = ioutil.WriteFile("ofile", sign, os.FileMode(0644))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
signdata, _ := ioutil.ReadFile("ofile")
|
||||
ok = privKey.Verify(msg, signdata) // 密钥验证
|
||||
if ok != true {
|
||||
fmt.Printf("Verify error\n")
|
||||
} else {
|
||||
fmt.Printf("Verify ok\n")
|
||||
}
|
||||
ok = pubKey.Verify(msg, signdata) // 公钥验证
|
||||
if ok != true {
|
||||
fmt.Printf("Verify error\n")
|
||||
} else {
|
||||
fmt.Printf("Verify ok\n")
|
||||
}
|
||||
templateReq := CertificateRequest{
|
||||
Subject: pkix.Name{
|
||||
CommonName: "test.example.com",
|
||||
Organization: []string{"Test"},
|
||||
},
|
||||
// SignatureAlgorithm: ECDSAWithSHA256,
|
||||
SignatureAlgorithm: SM2WithSM3,
|
||||
}
|
||||
_, err = CreateCertificateRequestToPem("req.pem", &templateReq, privKey)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
req, err := ReadCertificateRequestFromPem("req.pem")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = req.CheckSignature()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
} else {
|
||||
fmt.Printf("CheckSignature ok\n")
|
||||
}
|
||||
testExtKeyUsage := []ExtKeyUsage{ExtKeyUsageClientAuth, ExtKeyUsageServerAuth}
|
||||
testUnknownExtKeyUsage := []asn1.ObjectIdentifier{[]int{1, 2, 3}, []int{2, 59, 1}}
|
||||
extraExtensionData := []byte("extra extension")
|
||||
commonName := "test.example.com"
|
||||
template := Certificate{
|
||||
// SerialNumber is negative to ensure that negative
|
||||
// values are parsed. This is due to the prevalence of
|
||||
// buggy code that produces certificates with negative
|
||||
// serial numbers.
|
||||
SerialNumber: big.NewInt(-1),
|
||||
Subject: pkix.Name{
|
||||
CommonName: commonName,
|
||||
Organization: []string{"TEST"},
|
||||
Country: []string{"China"},
|
||||
ExtraNames: []pkix.AttributeTypeAndValue{
|
||||
{
|
||||
Type: []int{2, 5, 4, 42},
|
||||
Value: "Gopher",
|
||||
},
|
||||
// This should override the Country, above.
|
||||
{
|
||||
Type: []int{2, 5, 4, 6},
|
||||
Value: "NL",
|
||||
},
|
||||
},
|
||||
},
|
||||
NotBefore: time.Unix(1000, 0),
|
||||
NotAfter: time.Unix(100000, 0),
|
||||
|
||||
// SignatureAlgorithm: ECDSAWithSHA256,
|
||||
SignatureAlgorithm: SM2WithSM3,
|
||||
|
||||
SubjectKeyId: []byte{1, 2, 3, 4},
|
||||
KeyUsage: KeyUsageCertSign,
|
||||
|
||||
ExtKeyUsage: testExtKeyUsage,
|
||||
UnknownExtKeyUsage: testUnknownExtKeyUsage,
|
||||
|
||||
BasicConstraintsValid: true,
|
||||
IsCA: true,
|
||||
|
||||
OCSPServer: []string{"http://ocsp.example.com"},
|
||||
IssuingCertificateURL: []string{"http://crt.example.com/ca1.crt"},
|
||||
|
||||
DNSNames: []string{"test.example.com"},
|
||||
EmailAddresses: []string{"gopher@golang.org"},
|
||||
IPAddresses: []net.IP{net.IPv4(127, 0, 0, 1).To4(), net.ParseIP("2001:4860:0:2001::68")},
|
||||
|
||||
PolicyIdentifiers: []asn1.ObjectIdentifier{[]int{1, 2, 3}},
|
||||
PermittedDNSDomains: []string{".example.com", "example.com"},
|
||||
|
||||
CRLDistributionPoints: []string{"http://crl1.example.com/ca1.crl", "http://crl2.example.com/ca1.crl"},
|
||||
|
||||
ExtraExtensions: []pkix.Extension{
|
||||
{
|
||||
Id: []int{1, 2, 3, 4},
|
||||
Value: extraExtensionData,
|
||||
},
|
||||
// This extension should override the SubjectKeyId, above.
|
||||
{
|
||||
Id: oidExtensionSubjectKeyId,
|
||||
Critical: false,
|
||||
Value: []byte{0x04, 0x04, 4, 3, 2, 1},
|
||||
},
|
||||
},
|
||||
}
|
||||
pubKey, _ = priv.Public().(*PublicKey)
|
||||
ok, _ = CreateCertificateToPem("cert.pem", &template, &template, pubKey, privKey)
|
||||
if ok != true {
|
||||
fmt.Printf("failed to create cert file\n")
|
||||
}
|
||||
cert, err := ReadCertificateFromPem("cert.pem")
|
||||
if err != nil {
|
||||
fmt.Printf("failed to read cert file")
|
||||
}
|
||||
err = cert.CheckSignature(cert.SignatureAlgorithm, cert.RawTBSCertificate, cert.Signature)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
} else {
|
||||
fmt.Printf("CheckSignature ok\n")
|
||||
}
|
||||
}
|
||||
568
vendor/github.com/tjfoc/gmsm/sm2/verify.go
generated
vendored
Normal file
568
vendor/github.com/tjfoc/gmsm/sm2/verify.go
generated
vendored
Normal file
@@ -0,0 +1,568 @@
|
||||
/*
|
||||
Copyright Suzhou Tongji Fintech Research Institute 2017 All Rights Reserved.
|
||||
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.
|
||||
*/
|
||||
|
||||
package sm2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
type InvalidReason int
|
||||
|
||||
const (
|
||||
// NotAuthorizedToSign results when a certificate is signed by another
|
||||
// which isn't marked as a CA certificate.
|
||||
NotAuthorizedToSign InvalidReason = iota
|
||||
// Expired results when a certificate has expired, based on the time
|
||||
// given in the VerifyOptions.
|
||||
Expired
|
||||
// CANotAuthorizedForThisName results when an intermediate or root
|
||||
// certificate has a name constraint which doesn't include the name
|
||||
// being checked.
|
||||
CANotAuthorizedForThisName
|
||||
// TooManyIntermediates results when a path length constraint is
|
||||
// violated.
|
||||
TooManyIntermediates
|
||||
// IncompatibleUsage results when the certificate's key usage indicates
|
||||
// that it may only be used for a different purpose.
|
||||
IncompatibleUsage
|
||||
// NameMismatch results when the subject name of a parent certificate
|
||||
// does not match the issuer name in the child.
|
||||
NameMismatch
|
||||
)
|
||||
|
||||
// CertificateInvalidError results when an odd error occurs. Users of this
|
||||
// library probably want to handle all these errors uniformly.
|
||||
type CertificateInvalidError struct {
|
||||
Cert *Certificate
|
||||
Reason InvalidReason
|
||||
}
|
||||
|
||||
func (e CertificateInvalidError) Error() string {
|
||||
switch e.Reason {
|
||||
case NotAuthorizedToSign:
|
||||
return "x509: certificate is not authorized to sign other certificates"
|
||||
case Expired:
|
||||
return "x509: certificate has expired or is not yet valid"
|
||||
case CANotAuthorizedForThisName:
|
||||
return "x509: a root or intermediate certificate is not authorized to sign in this domain"
|
||||
case TooManyIntermediates:
|
||||
return "x509: too many intermediates for path length constraint"
|
||||
case IncompatibleUsage:
|
||||
return "x509: certificate specifies an incompatible key usage"
|
||||
case NameMismatch:
|
||||
return "x509: issuer name does not match subject from issuing certificate"
|
||||
}
|
||||
return "x509: unknown error"
|
||||
}
|
||||
|
||||
// HostnameError results when the set of authorized names doesn't match the
|
||||
// requested name.
|
||||
type HostnameError struct {
|
||||
Certificate *Certificate
|
||||
Host string
|
||||
}
|
||||
|
||||
func (h HostnameError) Error() string {
|
||||
c := h.Certificate
|
||||
|
||||
var valid string
|
||||
if ip := net.ParseIP(h.Host); ip != nil {
|
||||
// Trying to validate an IP
|
||||
if len(c.IPAddresses) == 0 {
|
||||
return "x509: cannot validate certificate for " + h.Host + " because it doesn't contain any IP SANs"
|
||||
}
|
||||
for _, san := range c.IPAddresses {
|
||||
if len(valid) > 0 {
|
||||
valid += ", "
|
||||
}
|
||||
valid += san.String()
|
||||
}
|
||||
} else {
|
||||
if len(c.DNSNames) > 0 {
|
||||
valid = strings.Join(c.DNSNames, ", ")
|
||||
} else {
|
||||
valid = c.Subject.CommonName
|
||||
}
|
||||
}
|
||||
|
||||
if len(valid) == 0 {
|
||||
return "x509: certificate is not valid for any names, but wanted to match " + h.Host
|
||||
}
|
||||
return "x509: certificate is valid for " + valid + ", not " + h.Host
|
||||
}
|
||||
|
||||
// UnknownAuthorityError results when the certificate issuer is unknown
|
||||
type UnknownAuthorityError struct {
|
||||
Cert *Certificate
|
||||
// hintErr contains an error that may be helpful in determining why an
|
||||
// authority wasn't found.
|
||||
hintErr error
|
||||
// hintCert contains a possible authority certificate that was rejected
|
||||
// because of the error in hintErr.
|
||||
hintCert *Certificate
|
||||
}
|
||||
|
||||
func (e UnknownAuthorityError) Error() string {
|
||||
s := "x509: certificate signed by unknown authority"
|
||||
if e.hintErr != nil {
|
||||
certName := e.hintCert.Subject.CommonName
|
||||
if len(certName) == 0 {
|
||||
if len(e.hintCert.Subject.Organization) > 0 {
|
||||
certName = e.hintCert.Subject.Organization[0]
|
||||
} else {
|
||||
certName = "serial:" + e.hintCert.SerialNumber.String()
|
||||
}
|
||||
}
|
||||
s += fmt.Sprintf(" (possibly because of %q while trying to verify candidate authority certificate %q)", e.hintErr, certName)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// SystemRootsError results when we fail to load the system root certificates.
|
||||
type SystemRootsError struct {
|
||||
Err error
|
||||
}
|
||||
|
||||
func (se SystemRootsError) Error() string {
|
||||
msg := "x509: failed to load system roots and no roots provided"
|
||||
if se.Err != nil {
|
||||
return msg + "; " + se.Err.Error()
|
||||
}
|
||||
return msg
|
||||
}
|
||||
|
||||
// errNotParsed is returned when a certificate without ASN.1 contents is
|
||||
// verified. Platform-specific verification needs the ASN.1 contents.
|
||||
var errNotParsed = errors.New("x509: missing ASN.1 contents; use ParseCertificate")
|
||||
|
||||
// VerifyOptions contains parameters for Certificate.Verify. It's a structure
|
||||
// because other PKIX verification APIs have ended up needing many options.
|
||||
type VerifyOptions struct {
|
||||
DNSName string
|
||||
Intermediates *CertPool
|
||||
Roots *CertPool // if nil, the system roots are used
|
||||
CurrentTime time.Time // if zero, the current time is used
|
||||
// KeyUsage specifies which Extended Key Usage values are acceptable.
|
||||
// An empty list means ExtKeyUsageServerAuth. Key usage is considered a
|
||||
// constraint down the chain which mirrors Windows CryptoAPI behavior,
|
||||
// but not the spec. To accept any key usage, include ExtKeyUsageAny.
|
||||
KeyUsages []ExtKeyUsage
|
||||
}
|
||||
|
||||
const (
|
||||
leafCertificate = iota
|
||||
intermediateCertificate
|
||||
rootCertificate
|
||||
)
|
||||
|
||||
func matchNameConstraint(domain, constraint string) bool {
|
||||
// The meaning of zero length constraints is not specified, but this
|
||||
// code follows NSS and accepts them as valid for everything.
|
||||
if len(constraint) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
if len(domain) < len(constraint) {
|
||||
return false
|
||||
}
|
||||
|
||||
prefixLen := len(domain) - len(constraint)
|
||||
if !strings.EqualFold(domain[prefixLen:], constraint) {
|
||||
return false
|
||||
}
|
||||
|
||||
if prefixLen == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
isSubdomain := domain[prefixLen-1] == '.'
|
||||
constraintHasLeadingDot := constraint[0] == '.'
|
||||
return isSubdomain != constraintHasLeadingDot
|
||||
}
|
||||
|
||||
// isValid performs validity checks on the c.
|
||||
func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *VerifyOptions) error {
|
||||
if len(currentChain) > 0 {
|
||||
child := currentChain[len(currentChain)-1]
|
||||
if !bytes.Equal(child.RawIssuer, c.RawSubject) {
|
||||
return CertificateInvalidError{c, NameMismatch}
|
||||
}
|
||||
}
|
||||
now := opts.CurrentTime
|
||||
if now.IsZero() {
|
||||
now = time.Now()
|
||||
}
|
||||
if now.Before(c.NotBefore) || now.After(c.NotAfter) {
|
||||
return CertificateInvalidError{c, Expired}
|
||||
}
|
||||
if len(c.PermittedDNSDomains) > 0 {
|
||||
ok := false
|
||||
for _, constraint := range c.PermittedDNSDomains {
|
||||
ok = matchNameConstraint(opts.DNSName, constraint)
|
||||
if ok {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !ok {
|
||||
return CertificateInvalidError{c, CANotAuthorizedForThisName}
|
||||
}
|
||||
}
|
||||
|
||||
// KeyUsage status flags are ignored. From Engineering Security, Peter
|
||||
// Gutmann: A European government CA marked its signing certificates as
|
||||
// being valid for encryption only, but no-one noticed. Another
|
||||
// European CA marked its signature keys as not being valid for
|
||||
// signatures. A different CA marked its own trusted root certificate
|
||||
// as being invalid for certificate signing. Another national CA
|
||||
// distributed a certificate to be used to encrypt data for the
|
||||
// country’s tax authority that was marked as only being usable for
|
||||
// digital signatures but not for encryption. Yet another CA reversed
|
||||
// the order of the bit flags in the keyUsage due to confusion over
|
||||
// encoding endianness, essentially setting a random keyUsage in
|
||||
// certificates that it issued. Another CA created a self-invalidating
|
||||
// certificate by adding a certificate policy statement stipulating
|
||||
// that the certificate had to be used strictly as specified in the
|
||||
// keyUsage, and a keyUsage containing a flag indicating that the RSA
|
||||
// encryption key could only be used for Diffie-Hellman key agreement.
|
||||
|
||||
if certType == intermediateCertificate && (!c.BasicConstraintsValid || !c.IsCA) {
|
||||
return CertificateInvalidError{c, NotAuthorizedToSign}
|
||||
}
|
||||
|
||||
if c.BasicConstraintsValid && c.MaxPathLen >= 0 {
|
||||
numIntermediates := len(currentChain) - 1
|
||||
if numIntermediates > c.MaxPathLen {
|
||||
return CertificateInvalidError{c, TooManyIntermediates}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Verify attempts to verify c by building one or more chains from c to a
|
||||
// certificate in opts.Roots, using certificates in opts.Intermediates if
|
||||
// needed. If successful, it returns one or more chains where the first
|
||||
// element of the chain is c and the last element is from opts.Roots.
|
||||
//
|
||||
// If opts.Roots is nil and system roots are unavailable the returned error
|
||||
// will be of type SystemRootsError.
|
||||
//
|
||||
// WARNING: this doesn't do any revocation checking.
|
||||
func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) {
|
||||
// Platform-specific verification needs the ASN.1 contents so
|
||||
// this makes the behavior consistent across platforms.
|
||||
if len(c.Raw) == 0 {
|
||||
return nil, errNotParsed
|
||||
}
|
||||
if opts.Intermediates != nil {
|
||||
for _, intermediate := range opts.Intermediates.certs {
|
||||
if len(intermediate.Raw) == 0 {
|
||||
return nil, errNotParsed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Use Windows's own verification and chain building.
|
||||
if opts.Roots == nil && runtime.GOOS == "windows" {
|
||||
return c.systemVerify(&opts)
|
||||
}
|
||||
|
||||
if len(c.UnhandledCriticalExtensions) > 0 {
|
||||
return nil, UnhandledCriticalExtension{}
|
||||
}
|
||||
|
||||
if opts.Roots == nil {
|
||||
opts.Roots = systemRootsPool()
|
||||
if opts.Roots == nil {
|
||||
return nil, SystemRootsError{systemRootsErr}
|
||||
}
|
||||
}
|
||||
|
||||
err = c.isValid(leafCertificate, nil, &opts)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(opts.DNSName) > 0 {
|
||||
err = c.VerifyHostname(opts.DNSName)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var candidateChains [][]*Certificate
|
||||
if opts.Roots.contains(c) {
|
||||
candidateChains = append(candidateChains, []*Certificate{c})
|
||||
} else {
|
||||
if candidateChains, err = c.buildChains(make(map[int][][]*Certificate), []*Certificate{c}, &opts); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
keyUsages := opts.KeyUsages
|
||||
if len(keyUsages) == 0 {
|
||||
keyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth}
|
||||
}
|
||||
|
||||
// If any key usage is acceptable then we're done.
|
||||
for _, usage := range keyUsages {
|
||||
if usage == ExtKeyUsageAny {
|
||||
chains = candidateChains
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
for _, candidate := range candidateChains {
|
||||
if checkChainForKeyUsage(candidate, keyUsages) {
|
||||
chains = append(chains, candidate)
|
||||
}
|
||||
}
|
||||
|
||||
if len(chains) == 0 {
|
||||
err = CertificateInvalidError{c, IncompatibleUsage}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate {
|
||||
n := make([]*Certificate, len(chain)+1)
|
||||
copy(n, chain)
|
||||
n[len(chain)] = cert
|
||||
return n
|
||||
}
|
||||
|
||||
func (c *Certificate) buildChains(cache map[int][][]*Certificate, currentChain []*Certificate, opts *VerifyOptions) (chains [][]*Certificate, err error) {
|
||||
possibleRoots, failedRoot, rootErr := opts.Roots.findVerifiedParents(c)
|
||||
nextRoot:
|
||||
for _, rootNum := range possibleRoots {
|
||||
root := opts.Roots.certs[rootNum]
|
||||
|
||||
for _, cert := range currentChain {
|
||||
if cert.Equal(root) {
|
||||
continue nextRoot
|
||||
}
|
||||
}
|
||||
|
||||
err = root.isValid(rootCertificate, currentChain, opts)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
chains = append(chains, appendToFreshChain(currentChain, root))
|
||||
}
|
||||
|
||||
possibleIntermediates, failedIntermediate, intermediateErr := opts.Intermediates.findVerifiedParents(c)
|
||||
nextIntermediate:
|
||||
for _, intermediateNum := range possibleIntermediates {
|
||||
intermediate := opts.Intermediates.certs[intermediateNum]
|
||||
for _, cert := range currentChain {
|
||||
if cert.Equal(intermediate) {
|
||||
continue nextIntermediate
|
||||
}
|
||||
}
|
||||
err = intermediate.isValid(intermediateCertificate, currentChain, opts)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
var childChains [][]*Certificate
|
||||
childChains, ok := cache[intermediateNum]
|
||||
if !ok {
|
||||
childChains, err = intermediate.buildChains(cache, appendToFreshChain(currentChain, intermediate), opts)
|
||||
cache[intermediateNum] = childChains
|
||||
}
|
||||
chains = append(chains, childChains...)
|
||||
}
|
||||
|
||||
if len(chains) > 0 {
|
||||
err = nil
|
||||
}
|
||||
|
||||
if len(chains) == 0 && err == nil {
|
||||
hintErr := rootErr
|
||||
hintCert := failedRoot
|
||||
if hintErr == nil {
|
||||
hintErr = intermediateErr
|
||||
hintCert = failedIntermediate
|
||||
}
|
||||
err = UnknownAuthorityError{c, hintErr, hintCert}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func matchHostnames(pattern, host string) bool {
|
||||
host = strings.TrimSuffix(host, ".")
|
||||
pattern = strings.TrimSuffix(pattern, ".")
|
||||
|
||||
if len(pattern) == 0 || len(host) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
patternParts := strings.Split(pattern, ".")
|
||||
hostParts := strings.Split(host, ".")
|
||||
|
||||
if len(patternParts) != len(hostParts) {
|
||||
return false
|
||||
}
|
||||
|
||||
for i, patternPart := range patternParts {
|
||||
if i == 0 && patternPart == "*" {
|
||||
continue
|
||||
}
|
||||
if patternPart != hostParts[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// toLowerCaseASCII returns a lower-case version of in. See RFC 6125 6.4.1. We use
|
||||
// an explicitly ASCII function to avoid any sharp corners resulting from
|
||||
// performing Unicode operations on DNS labels.
|
||||
func toLowerCaseASCII(in string) string {
|
||||
// If the string is already lower-case then there's nothing to do.
|
||||
isAlreadyLowerCase := true
|
||||
for _, c := range in {
|
||||
if c == utf8.RuneError {
|
||||
// If we get a UTF-8 error then there might be
|
||||
// upper-case ASCII bytes in the invalid sequence.
|
||||
isAlreadyLowerCase = false
|
||||
break
|
||||
}
|
||||
if 'A' <= c && c <= 'Z' {
|
||||
isAlreadyLowerCase = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if isAlreadyLowerCase {
|
||||
return in
|
||||
}
|
||||
|
||||
out := []byte(in)
|
||||
for i, c := range out {
|
||||
if 'A' <= c && c <= 'Z' {
|
||||
out[i] += 'a' - 'A'
|
||||
}
|
||||
}
|
||||
return string(out)
|
||||
}
|
||||
|
||||
// VerifyHostname returns nil if c is a valid certificate for the named host.
|
||||
// Otherwise it returns an error describing the mismatch.
|
||||
func (c *Certificate) VerifyHostname(h string) error {
|
||||
// IP addresses may be written in [ ].
|
||||
candidateIP := h
|
||||
if len(h) >= 3 && h[0] == '[' && h[len(h)-1] == ']' {
|
||||
candidateIP = h[1 : len(h)-1]
|
||||
}
|
||||
if ip := net.ParseIP(candidateIP); ip != nil {
|
||||
// We only match IP addresses against IP SANs.
|
||||
// https://tools.ietf.org/html/rfc6125#appendix-B.2
|
||||
for _, candidate := range c.IPAddresses {
|
||||
if ip.Equal(candidate) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return HostnameError{c, candidateIP}
|
||||
}
|
||||
|
||||
lowered := toLowerCaseASCII(h)
|
||||
|
||||
if len(c.DNSNames) > 0 {
|
||||
for _, match := range c.DNSNames {
|
||||
if matchHostnames(toLowerCaseASCII(match), lowered) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
// If Subject Alt Name is given, we ignore the common name.
|
||||
} else if matchHostnames(toLowerCaseASCII(c.Subject.CommonName), lowered) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return HostnameError{c, h}
|
||||
}
|
||||
|
||||
func checkChainForKeyUsage(chain []*Certificate, keyUsages []ExtKeyUsage) bool {
|
||||
usages := make([]ExtKeyUsage, len(keyUsages))
|
||||
copy(usages, keyUsages)
|
||||
|
||||
if len(chain) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
usagesRemaining := len(usages)
|
||||
|
||||
// We walk down the list and cross out any usages that aren't supported
|
||||
// by each certificate. If we cross out all the usages, then the chain
|
||||
// is unacceptable.
|
||||
|
||||
NextCert:
|
||||
for i := len(chain) - 1; i >= 0; i-- {
|
||||
cert := chain[i]
|
||||
if len(cert.ExtKeyUsage) == 0 && len(cert.UnknownExtKeyUsage) == 0 {
|
||||
// The certificate doesn't have any extended key usage specified.
|
||||
continue
|
||||
}
|
||||
|
||||
for _, usage := range cert.ExtKeyUsage {
|
||||
if usage == ExtKeyUsageAny {
|
||||
// The certificate is explicitly good for any usage.
|
||||
continue NextCert
|
||||
}
|
||||
}
|
||||
|
||||
const invalidUsage ExtKeyUsage = -1
|
||||
|
||||
NextRequestedUsage:
|
||||
for i, requestedUsage := range usages {
|
||||
if requestedUsage == invalidUsage {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, usage := range cert.ExtKeyUsage {
|
||||
if requestedUsage == usage {
|
||||
continue NextRequestedUsage
|
||||
} else if requestedUsage == ExtKeyUsageServerAuth &&
|
||||
(usage == ExtKeyUsageNetscapeServerGatedCrypto ||
|
||||
usage == ExtKeyUsageMicrosoftServerGatedCrypto) {
|
||||
// In order to support COMODO
|
||||
// certificate chains, we have to
|
||||
// accept Netscape or Microsoft SGC
|
||||
// usages as equal to ServerAuth.
|
||||
continue NextRequestedUsage
|
||||
}
|
||||
}
|
||||
|
||||
usages[i] = invalidUsage
|
||||
usagesRemaining--
|
||||
if usagesRemaining == 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
2526
vendor/github.com/tjfoc/gmsm/sm2/x509.go
generated
vendored
Normal file
2526
vendor/github.com/tjfoc/gmsm/sm2/x509.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user