forked from tjfoc/gmsm
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
sm2签名验证不再使用空uid值改为使用默认uid值。新增sm2的P12证书生成与解析。
- Loading branch information
czdsdo
committed
May 14, 2020
1 parent
2d54c72
commit 55900cf
Showing
11 changed files
with
1,697 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
// Copyright 2015 The Go Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
package pkcs12 | ||
|
||
import ( | ||
"errors" | ||
"unicode/utf16" | ||
) | ||
|
||
// bmpString returns s encoded in UCS-2 with a zero terminator. | ||
func bmpString(s string) ([]byte, error) { | ||
// References: | ||
// https://tools.ietf.org/html/rfc7292#appendix-B.1 | ||
// http://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_Multilingual_Plane | ||
// - non-BMP characters are encoded in UTF 16 by using a surrogate pair of 16-bit codes | ||
// EncodeRune returns 0xfffd if the rune does not need special encoding | ||
// - the above RFC provides the info that BMPStrings are NULL terminated. | ||
|
||
ret := make([]byte, 0, 2*len(s)+2) | ||
|
||
for _, r := range s { | ||
if t, _ := utf16.EncodeRune(r); t != 0xfffd { | ||
return nil, errors.New("go-pkcs12: string contains characters that cannot be encoded in UCS-2") | ||
} | ||
ret = append(ret, byte(r/256), byte(r%256)) | ||
} | ||
|
||
return append(ret, 0, 0), nil | ||
} | ||
|
||
func decodeBMPString(bmpString []byte) (string, error) { | ||
if len(bmpString)%2 != 0 { | ||
return "", errors.New("go-pkcs12: odd-length BMP string") | ||
} | ||
|
||
// strip terminator if present | ||
if l := len(bmpString); l >= 2 && bmpString[l-1] == 0 && bmpString[l-2] == 0 { | ||
bmpString = bmpString[:l-2] | ||
} | ||
|
||
s := make([]uint16, 0, len(bmpString)/2) | ||
for len(bmpString) > 0 { | ||
s = append(s, uint16(bmpString[0])<<8+uint16(bmpString[1])) | ||
bmpString = bmpString[2:] | ||
} | ||
|
||
return string(utf16.Decode(s)), nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
// Copyright 2015 The Go Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
package pkcs12 | ||
|
||
import ( | ||
"bytes" | ||
"crypto/cipher" | ||
"crypto/des" | ||
"crypto/x509/pkix" | ||
"encoding/asn1" | ||
"errors" | ||
) | ||
|
||
var ( | ||
oidPBEWithSHAAnd3KeyTripleDESCBC = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 1, 3}) | ||
oidPBEWithSHAAnd40BitRC2CBC = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 1, 6}) | ||
) | ||
|
||
// pbeCipher is an abstraction of a PKCS#12 cipher. | ||
type pbeCipher interface { | ||
// create returns a cipher.Block given a key. | ||
create(key []byte) (cipher.Block, error) | ||
// deriveKey returns a key derived from the given password and salt. | ||
deriveKey(salt, password []byte, iterations int) []byte | ||
// deriveKey returns an IV derived from the given password and salt. | ||
deriveIV(salt, password []byte, iterations int) []byte | ||
} | ||
|
||
type shaWithTripleDESCBC struct{} | ||
|
||
func (shaWithTripleDESCBC) create(key []byte) (cipher.Block, error) { | ||
return des.NewTripleDESCipher(key) | ||
} | ||
|
||
func (shaWithTripleDESCBC) deriveKey(salt, password []byte, iterations int) []byte { | ||
return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 1, 24) | ||
} | ||
|
||
func (shaWithTripleDESCBC) deriveIV(salt, password []byte, iterations int) []byte { | ||
return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 2, 8) | ||
} | ||
|
||
type shaWith40BitRC2CBC struct{} | ||
|
||
func (shaWith40BitRC2CBC) create(key []byte) (cipher.Block, error) { | ||
return New(key, len(key)*8) | ||
} | ||
|
||
func (shaWith40BitRC2CBC) deriveKey(salt, password []byte, iterations int) []byte { | ||
return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 1, 5) | ||
} | ||
|
||
func (shaWith40BitRC2CBC) deriveIV(salt, password []byte, iterations int) []byte { | ||
return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 2, 8) | ||
} | ||
|
||
type pbeParams struct { | ||
Salt []byte | ||
Iterations int | ||
} | ||
|
||
func pbeCipherFor(algorithm pkix.AlgorithmIdentifier, password []byte) (cipher.Block, []byte, error) { | ||
var cipherType pbeCipher | ||
|
||
switch { | ||
case algorithm.Algorithm.Equal(oidPBEWithSHAAnd3KeyTripleDESCBC): | ||
cipherType = shaWithTripleDESCBC{} | ||
case algorithm.Algorithm.Equal(oidPBEWithSHAAnd40BitRC2CBC): | ||
cipherType = shaWith40BitRC2CBC{} | ||
default: | ||
return nil, nil, NotImplementedError("algorithm " + algorithm.Algorithm.String() + " is not supported") | ||
} | ||
|
||
var params pbeParams | ||
if err := unmarshal(algorithm.Parameters.FullBytes, ¶ms); err != nil { | ||
return nil, nil, err | ||
} | ||
|
||
key := cipherType.deriveKey(params.Salt, password, params.Iterations) | ||
iv := cipherType.deriveIV(params.Salt, password, params.Iterations) | ||
|
||
block, err := cipherType.create(key) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
|
||
return block, iv, nil | ||
} | ||
|
||
func pbDecrypterFor(algorithm pkix.AlgorithmIdentifier, password []byte) (cipher.BlockMode, int, error) { | ||
block, iv, err := pbeCipherFor(algorithm, password) | ||
if err != nil { | ||
return nil, 0, err | ||
} | ||
|
||
return cipher.NewCBCDecrypter(block, iv), block.BlockSize(), nil | ||
} | ||
|
||
func pbDecrypt(info decryptable, password []byte) (decrypted []byte, err error) { | ||
cbc, blockSize, err := pbDecrypterFor(info.Algorithm(), password) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
encrypted := info.Data() | ||
if len(encrypted) == 0 { | ||
return nil, errors.New("go-pkcs12: empty encrypted data") | ||
} | ||
if len(encrypted)%blockSize != 0 { | ||
return nil, errors.New("go-pkcs12: input is not a multiple of the block size") | ||
} | ||
decrypted = make([]byte, len(encrypted)) | ||
cbc.CryptBlocks(decrypted, encrypted) | ||
|
||
psLen := int(decrypted[len(decrypted)-1]) | ||
if psLen == 0 || psLen > blockSize { | ||
return nil, ErrDecryption | ||
} | ||
|
||
if len(decrypted) < psLen { | ||
return nil, ErrDecryption | ||
} | ||
ps := decrypted[len(decrypted)-psLen:] | ||
decrypted = decrypted[:len(decrypted)-psLen] | ||
if bytes.Compare(ps, bytes.Repeat([]byte{byte(psLen)}, psLen)) != 0 { | ||
return nil, ErrDecryption | ||
} | ||
|
||
return | ||
} | ||
|
||
// decryptable abstracts a object that contains ciphertext. | ||
type decryptable interface { | ||
Algorithm() pkix.AlgorithmIdentifier | ||
Data() []byte | ||
} | ||
|
||
func pbEncrypterFor(algorithm pkix.AlgorithmIdentifier, password []byte) (cipher.BlockMode, int, error) { | ||
block, iv, err := pbeCipherFor(algorithm, password) | ||
if err != nil { | ||
return nil, 0, err | ||
} | ||
|
||
return cipher.NewCBCEncrypter(block, iv), block.BlockSize(), nil | ||
} | ||
|
||
func pbEncrypt(info encryptable, decrypted []byte, password []byte) error { | ||
cbc, blockSize, err := pbEncrypterFor(info.Algorithm(), password) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
psLen := blockSize - len(decrypted)%blockSize | ||
encrypted := make([]byte, len(decrypted)+psLen) | ||
copy(encrypted[:len(decrypted)], decrypted) | ||
copy(encrypted[len(decrypted):], bytes.Repeat([]byte{byte(psLen)}, psLen)) | ||
cbc.CryptBlocks(encrypted, encrypted) | ||
|
||
info.SetData(encrypted) | ||
|
||
return nil | ||
} | ||
|
||
// encryptable abstracts a object that contains ciphertext. | ||
type encryptable interface { | ||
Algorithm() pkix.AlgorithmIdentifier | ||
SetData([]byte) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
// Copyright 2015 The Go Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
package pkcs12 | ||
|
||
import "errors" | ||
|
||
var ( | ||
// ErrDecryption represents a failure to decrypt the input. | ||
ErrDecryption = errors.New("go-pkcs12: decryption error, incorrect padding") | ||
|
||
// ErrIncorrectPassword is returned when an incorrect password is detected. | ||
// Usually, P12/PFX data is signed to be able to verify the password. | ||
ErrIncorrectPassword = errors.New("go-pkcs12: decryption password incorrect") | ||
) | ||
|
||
// NotImplementedError indicates that the input is not currently supported. | ||
type NotImplementedError string | ||
|
||
func (e NotImplementedError) Error() string { | ||
return "go-pkcs12: " + string(e) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
// Copyright 2015 The Go Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
package pkcs12 | ||
|
||
import ( | ||
"crypto/hmac" | ||
"crypto/sha1" | ||
"crypto/x509/pkix" | ||
"encoding/asn1" | ||
) | ||
|
||
type macData struct { | ||
Mac digestInfo | ||
MacSalt []byte | ||
Iterations int `asn1:"optional,default:1"` | ||
} | ||
|
||
// from PKCS#7: | ||
type digestInfo struct { | ||
Algorithm pkix.AlgorithmIdentifier | ||
Digest []byte | ||
} | ||
|
||
var ( | ||
oidSHA1 = asn1.ObjectIdentifier([]int{1, 3, 14, 3, 2, 26}) | ||
) | ||
|
||
func verifyMac(macData *macData, message, password []byte) error { | ||
if !macData.Mac.Algorithm.Algorithm.Equal(oidSHA1) { | ||
return NotImplementedError("unknown digest algorithm: " + macData.Mac.Algorithm.Algorithm.String()) | ||
} | ||
|
||
key := pbkdf(sha1Sum, 20, 64, macData.MacSalt, password, macData.Iterations, 3, 20) | ||
|
||
mac := hmac.New(sha1.New, key) | ||
mac.Write(message) | ||
expectedMAC := mac.Sum(nil) | ||
|
||
if !hmac.Equal(macData.Mac.Digest, expectedMAC) { | ||
return ErrIncorrectPassword | ||
} | ||
return nil | ||
} | ||
|
||
func computeMac(macData *macData, message, password []byte) error { | ||
if !macData.Mac.Algorithm.Algorithm.Equal(oidSHA1) { | ||
return NotImplementedError("unknown digest algorithm: " + macData.Mac.Algorithm.Algorithm.String()) | ||
} | ||
|
||
key := pbkdf(sha1Sum, 20, 64, macData.MacSalt, password, macData.Iterations, 3, 20) | ||
|
||
mac := hmac.New(sha1.New, key) | ||
mac.Write(message) | ||
macData.Mac.Digest = mac.Sum(nil) | ||
|
||
return nil | ||
} |
Oops, something went wrong.