mirror of
https://github.com/emmansun/gmsm.git
synced 2025-04-27 20:56:18 +08:00
Merge branch 'main' of https://github.com/emmansun/gmsm
This commit is contained in:
commit
2574f2447c
@ -49,9 +49,9 @@ func isPrintable(b byte) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// parseASN1String parses the ASN.1 string types T61String, PrintableString,
|
// parseASN1String parses the ASN.1 string types T61String, PrintableString,
|
||||||
// UTF8String, BMPString, and IA5String. This is mostly copied from the
|
// UTF8String, BMPString, IA5String, and NumericString. This is mostly copied
|
||||||
// respective encoding/asn1.parse... methods, rather than just increasing
|
// from the respective encoding/asn1.parse... methods, rather than just
|
||||||
// the API surface of that package.
|
// increasing the API surface of that package.
|
||||||
func parseASN1String(tag cryptobyte_asn1.Tag, value []byte) (string, error) {
|
func parseASN1String(tag cryptobyte_asn1.Tag, value []byte) (string, error) {
|
||||||
switch tag {
|
switch tag {
|
||||||
case cryptobyte_asn1.T61String:
|
case cryptobyte_asn1.T61String:
|
||||||
@ -91,6 +91,13 @@ func parseASN1String(tag cryptobyte_asn1.Tag, value []byte) (string, error) {
|
|||||||
return "", errors.New("invalid IA5String")
|
return "", errors.New("invalid IA5String")
|
||||||
}
|
}
|
||||||
return s, nil
|
return s, nil
|
||||||
|
case cryptobyte_asn1.Tag(asn1.TagNumericString):
|
||||||
|
for _, b := range value {
|
||||||
|
if !('0' <= b && b <= '9' || b == ' ') {
|
||||||
|
return "", errors.New("invalid NumericString")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return string(value), nil
|
||||||
}
|
}
|
||||||
return "", fmt.Errorf("unsupported string type: %v", tag)
|
return "", fmt.Errorf("unsupported string type: %v", tag)
|
||||||
}
|
}
|
||||||
|
33
smx509/pkcs1.go
Normal file
33
smx509/pkcs1.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package smx509
|
||||||
|
|
||||||
|
import "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
|
||||||
|
}
|
||||||
|
|
||||||
|
// pkcs1PublicKey reflects the ASN.1 structure of a PKCS #1 public key.
|
||||||
|
type pkcs1PublicKey struct {
|
||||||
|
N *big.Int
|
||||||
|
E int
|
||||||
|
}
|
@ -10,7 +10,7 @@ import (
|
|||||||
"github.com/emmansun/gmsm/sm2"
|
"github.com/emmansun/gmsm/sm2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// pkcs8 reflects an ASN.1, PKCS#8 PrivateKey. See
|
// pkcs8 reflects an ASN.1, PKCS #8 PrivateKey. See
|
||||||
// ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-8/pkcs-8v1_2.asn
|
// ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-8/pkcs-8v1_2.asn
|
||||||
// and RFC 5208.
|
// and RFC 5208.
|
||||||
type pkcs8 struct {
|
type pkcs8 struct {
|
||||||
@ -20,7 +20,7 @@ type pkcs8 struct {
|
|||||||
// optional attributes omitted.
|
// optional attributes omitted.
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParsePKCS8PrivateKey parses an unencrypted private key in PKCS#8, ASN.1 DER form.
|
// ParsePKCS8PrivateKey parses an unencrypted private key in PKCS #8, ASN.1 DER form.
|
||||||
//
|
//
|
||||||
// It returns a *rsa.PrivateKey, a *ecdsa.PrivateKey, or a ed25519.PrivateKey.
|
// It returns a *rsa.PrivateKey, a *ecdsa.PrivateKey, or a ed25519.PrivateKey.
|
||||||
// More types might be supported in the future.
|
// More types might be supported in the future.
|
||||||
@ -57,7 +57,7 @@ func ParsePKCS8PrivateKey(der []byte) (key interface{}, err error) {
|
|||||||
return key, err
|
return key, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalPKCS8PrivateKey converts a private key to PKCS#8, ASN.1 DER form.
|
// MarshalPKCS8PrivateKey converts a private key to PKCS #8, ASN.1 DER form.
|
||||||
//
|
//
|
||||||
// The following key types are currently supported: *rsa.PrivateKey, *ecdsa.PrivateKey
|
// The following key types are currently supported: *rsa.PrivateKey, *ecdsa.PrivateKey
|
||||||
// and ed25519.PrivateKey. Unsupported key types result in an error.
|
// and ed25519.PrivateKey. Unsupported key types result in an error.
|
||||||
|
@ -11,30 +11,6 @@ import (
|
|||||||
"github.com/emmansun/gmsm/sm2"
|
"github.com/emmansun/gmsm/sm2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
const ecPrivKeyVersion = 1
|
const ecPrivKeyVersion = 1
|
||||||
|
|
||||||
// ecPrivateKey reflects an ASN.1 Elliptic Curve Private Key Structure.
|
// ecPrivateKey reflects an ASN.1 Elliptic Curve Private Key Structure.
|
||||||
|
289
smx509/verify.go
289
smx509/verify.go
@ -244,6 +244,143 @@ func parseRFC2821Mailbox(in string) (mailbox rfc2821Mailbox, ok bool) {
|
|||||||
return mailbox, true
|
return mailbox, true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// domainToReverseLabels converts a textual domain name like foo.example.com to
|
||||||
|
// the list of labels in reverse order, e.g. ["com", "example", "foo"].
|
||||||
|
func domainToReverseLabels(domain string) (reverseLabels []string, ok bool) {
|
||||||
|
for len(domain) > 0 {
|
||||||
|
if i := strings.LastIndexByte(domain, '.'); i == -1 {
|
||||||
|
reverseLabels = append(reverseLabels, domain)
|
||||||
|
domain = ""
|
||||||
|
} else {
|
||||||
|
reverseLabels = append(reverseLabels, domain[i+1:])
|
||||||
|
domain = domain[:i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(reverseLabels) > 0 && len(reverseLabels[0]) == 0 {
|
||||||
|
// An empty label at the end indicates an absolute value.
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, label := range reverseLabels {
|
||||||
|
if len(label) == 0 {
|
||||||
|
// Empty labels are otherwise invalid.
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range label {
|
||||||
|
if c < 33 || c > 126 {
|
||||||
|
// Invalid character.
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return reverseLabels, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func matchEmailConstraint(mailbox rfc2821Mailbox, constraint string) (bool, error) {
|
||||||
|
// If the constraint contains an @, then it specifies an exact mailbox
|
||||||
|
// name.
|
||||||
|
if strings.Contains(constraint, "@") {
|
||||||
|
constraintMailbox, ok := parseRFC2821Mailbox(constraint)
|
||||||
|
if !ok {
|
||||||
|
return false, fmt.Errorf("x509: internal error: cannot parse constraint %q", constraint)
|
||||||
|
}
|
||||||
|
return mailbox.local == constraintMailbox.local && strings.EqualFold(mailbox.domain, constraintMailbox.domain), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise the constraint is like a DNS constraint of the domain part
|
||||||
|
// of the mailbox.
|
||||||
|
return matchDomainConstraint(mailbox.domain, constraint)
|
||||||
|
}
|
||||||
|
|
||||||
|
func matchURIConstraint(uri *url.URL, constraint string) (bool, error) {
|
||||||
|
// From RFC 5280, Section 4.2.1.10:
|
||||||
|
// “a uniformResourceIdentifier that does not include an authority
|
||||||
|
// component with a host name specified as a fully qualified domain
|
||||||
|
// name (e.g., if the URI either does not include an authority
|
||||||
|
// component or includes an authority component in which the host name
|
||||||
|
// is specified as an IP address), then the application MUST reject the
|
||||||
|
// certificate.”
|
||||||
|
|
||||||
|
host := uri.Host
|
||||||
|
if len(host) == 0 {
|
||||||
|
return false, fmt.Errorf("URI with empty host (%q) cannot be matched against constraints", uri.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Contains(host, ":") && !strings.HasSuffix(host, "]") {
|
||||||
|
var err error
|
||||||
|
host, _, err = net.SplitHostPort(uri.Host)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") ||
|
||||||
|
net.ParseIP(host) != nil {
|
||||||
|
return false, fmt.Errorf("URI with IP (%q) cannot be matched against constraints", uri.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
return matchDomainConstraint(host, constraint)
|
||||||
|
}
|
||||||
|
|
||||||
|
func matchIPConstraint(ip net.IP, constraint *net.IPNet) (bool, error) {
|
||||||
|
if len(ip) != len(constraint.IP) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range ip {
|
||||||
|
if mask := constraint.Mask[i]; ip[i]&mask != constraint.IP[i]&mask {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func matchDomainConstraint(domain, constraint string) (bool, error) {
|
||||||
|
// The meaning of zero length constraints is not specified, but this
|
||||||
|
// code follows NSS and accepts them as matching everything.
|
||||||
|
if len(constraint) == 0 {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
domainLabels, ok := domainToReverseLabels(domain)
|
||||||
|
if !ok {
|
||||||
|
return false, fmt.Errorf("x509: internal error: cannot parse domain %q", domain)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RFC 5280 says that a leading period in a domain name means that at
|
||||||
|
// least one label must be prepended, but only for URI and email
|
||||||
|
// constraints, not DNS constraints. The code also supports that
|
||||||
|
// behaviour for DNS constraints.
|
||||||
|
|
||||||
|
mustHaveSubdomains := false
|
||||||
|
if constraint[0] == '.' {
|
||||||
|
mustHaveSubdomains = true
|
||||||
|
constraint = constraint[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
constraintLabels, ok := domainToReverseLabels(constraint)
|
||||||
|
if !ok {
|
||||||
|
return false, fmt.Errorf("x509: internal error: cannot parse domain %q", constraint)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(domainLabels) < len(constraintLabels) ||
|
||||||
|
(mustHaveSubdomains && len(domainLabels) == len(constraintLabels)) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, constraintLabel := range constraintLabels {
|
||||||
|
if !strings.EqualFold(constraintLabel, domainLabels[i]) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
// checkNameConstraints checks that c permits a child certificate to claim the
|
// checkNameConstraints checks that c permits a child certificate to claim the
|
||||||
// given name, of type nameType. The argument parsedName contains the parsed
|
// given name, of type nameType. The argument parsedName contains the parsed
|
||||||
// form of name, suitable for passing to the match function. The total number
|
// form of name, suitable for passing to the match function. The total number
|
||||||
@ -304,41 +441,6 @@ func (c *Certificate) checkNameConstraints(count *int,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// domainToReverseLabels converts a textual domain name like foo.example.com to
|
|
||||||
// the list of labels in reverse order, e.g. ["com", "example", "foo"].
|
|
||||||
func domainToReverseLabels(domain string) (reverseLabels []string, ok bool) {
|
|
||||||
for len(domain) > 0 {
|
|
||||||
if i := strings.LastIndexByte(domain, '.'); i == -1 {
|
|
||||||
reverseLabels = append(reverseLabels, domain)
|
|
||||||
domain = ""
|
|
||||||
} else {
|
|
||||||
reverseLabels = append(reverseLabels, domain[i+1:])
|
|
||||||
domain = domain[:i]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(reverseLabels) > 0 && len(reverseLabels[0]) == 0 {
|
|
||||||
// An empty label at the end indicates an absolute value.
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, label := range reverseLabels {
|
|
||||||
if len(label) == 0 {
|
|
||||||
// Empty labels are otherwise invalid.
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, c := range label {
|
|
||||||
if c < 33 || c > 126 {
|
|
||||||
// Invalid character.
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return reverseLabels, true
|
|
||||||
}
|
|
||||||
|
|
||||||
// isValid performs validity checks on c given that it is a candidate to append
|
// isValid performs validity checks on c given that it is a candidate to append
|
||||||
// to the chain in currentChain.
|
// to the chain in currentChain.
|
||||||
func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *VerifyOptions) error {
|
func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *VerifyOptions) error {
|
||||||
@ -501,6 +603,12 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
|
|||||||
// the name being validated. Note that DirectoryName constraints are not
|
// the name being validated. Note that DirectoryName constraints are not
|
||||||
// supported.
|
// supported.
|
||||||
//
|
//
|
||||||
|
// Name constraint validation follows the rules from RFC 5280, with the
|
||||||
|
// addition that DNS name constraints may use the leading period format
|
||||||
|
// defined for emails and URIs. When a constraint has a leading period
|
||||||
|
// it indicates that at least one additional label must be prepended to
|
||||||
|
// the constrained name to be considered valid.
|
||||||
|
//
|
||||||
// Extended Key Usage values are enforced nested down a chain, so an intermediate
|
// Extended Key Usage values are enforced nested down a chain, so an intermediate
|
||||||
// or root that enumerates EKUs prevents a leaf from asserting an EKU not in that
|
// or root that enumerates EKUs prevents a leaf from asserting an EKU not in that
|
||||||
// list. (While this is not specified, it is common practice in order to limit
|
// list. (While this is not specified, it is common practice in order to limit
|
||||||
@ -523,8 +631,8 @@ func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err e
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use Windows's own verification and chain building.
|
// Use platform verifiers, where available, if Roots is from SystemCertPool.
|
||||||
if opts.Roots == nil && runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
if opts.Roots == nil {
|
if opts.Roots == nil {
|
||||||
return c.systemVerify(&opts)
|
return c.systemVerify(&opts)
|
||||||
}
|
}
|
||||||
@ -600,7 +708,7 @@ func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate
|
|||||||
}
|
}
|
||||||
|
|
||||||
// maxChainSignatureChecks is the maximum number of CheckSignatureFrom calls
|
// maxChainSignatureChecks is the maximum number of CheckSignatureFrom calls
|
||||||
// that an invocation of buildChains will (tranistively) make. Most chains are
|
// that an invocation of buildChains will (transitively) make. Most chains are
|
||||||
// less than 15 certificates long, so this leaves space for multiple chains and
|
// less than 15 certificates long, so this leaves space for multiple chains and
|
||||||
// for failed checks due to different intermediates having the same Subject.
|
// for failed checks due to different intermediates having the same Subject.
|
||||||
const maxChainSignatureChecks = 100
|
const maxChainSignatureChecks = 100
|
||||||
@ -713,7 +821,7 @@ func validHostname(host string, isPattern bool) bool {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if c == '_' {
|
if c == '_' {
|
||||||
// Not valid characters in hostnames, but commonly
|
// Not a valid character in hostnames, but commonly
|
||||||
// found in deployments outside the WebPKI.
|
// found in deployments outside the WebPKI.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -835,6 +943,7 @@ func (c *Certificate) VerifyHostname(h string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return x509.HostnameError{Certificate: c.asX509(), Host: h}
|
return x509.HostnameError{Certificate: c.asX509(), Host: h}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -899,105 +1008,3 @@ NextCert:
|
|||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func matchEmailConstraint(mailbox rfc2821Mailbox, constraint string) (bool, error) {
|
|
||||||
// If the constraint contains an @, then it specifies an exact mailbox
|
|
||||||
// name.
|
|
||||||
if strings.Contains(constraint, "@") {
|
|
||||||
constraintMailbox, ok := parseRFC2821Mailbox(constraint)
|
|
||||||
if !ok {
|
|
||||||
return false, fmt.Errorf("x509: internal error: cannot parse constraint %q", constraint)
|
|
||||||
}
|
|
||||||
return mailbox.local == constraintMailbox.local && strings.EqualFold(mailbox.domain, constraintMailbox.domain), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise the constraint is like a DNS constraint of the domain part
|
|
||||||
// of the mailbox.
|
|
||||||
return matchDomainConstraint(mailbox.domain, constraint)
|
|
||||||
}
|
|
||||||
|
|
||||||
func matchURIConstraint(uri *url.URL, constraint string) (bool, error) {
|
|
||||||
// From RFC 5280, Section 4.2.1.10:
|
|
||||||
// “a uniformResourceIdentifier that does not include an authority
|
|
||||||
// component with a host name specified as a fully qualified domain
|
|
||||||
// name (e.g., if the URI either does not include an authority
|
|
||||||
// component or includes an authority component in which the host name
|
|
||||||
// is specified as an IP address), then the application MUST reject the
|
|
||||||
// certificate.”
|
|
||||||
|
|
||||||
host := uri.Host
|
|
||||||
if len(host) == 0 {
|
|
||||||
return false, fmt.Errorf("URI with empty host (%q) cannot be matched against constraints", uri.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.Contains(host, ":") && !strings.HasSuffix(host, "]") {
|
|
||||||
var err error
|
|
||||||
host, _, err = net.SplitHostPort(uri.Host)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") ||
|
|
||||||
net.ParseIP(host) != nil {
|
|
||||||
return false, fmt.Errorf("URI with IP (%q) cannot be matched against constraints", uri.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
return matchDomainConstraint(host, constraint)
|
|
||||||
}
|
|
||||||
|
|
||||||
func matchIPConstraint(ip net.IP, constraint *net.IPNet) (bool, error) {
|
|
||||||
if len(ip) != len(constraint.IP) {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := range ip {
|
|
||||||
if mask := constraint.Mask[i]; ip[i]&mask != constraint.IP[i]&mask {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func matchDomainConstraint(domain, constraint string) (bool, error) {
|
|
||||||
// The meaning of zero length constraints is not specified, but this
|
|
||||||
// code follows NSS and accepts them as matching everything.
|
|
||||||
if len(constraint) == 0 {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
domainLabels, ok := domainToReverseLabels(domain)
|
|
||||||
if !ok {
|
|
||||||
return false, fmt.Errorf("x509: internal error: cannot parse domain %q", domain)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RFC 5280 says that a leading period in a domain name means that at
|
|
||||||
// least one label must be prepended, but only for URI and email
|
|
||||||
// constraints, not DNS constraints. The code also supports that
|
|
||||||
// behaviour for DNS constraints.
|
|
||||||
|
|
||||||
mustHaveSubdomains := false
|
|
||||||
if constraint[0] == '.' {
|
|
||||||
mustHaveSubdomains = true
|
|
||||||
constraint = constraint[1:]
|
|
||||||
}
|
|
||||||
|
|
||||||
constraintLabels, ok := domainToReverseLabels(constraint)
|
|
||||||
if !ok {
|
|
||||||
return false, fmt.Errorf("x509: internal error: cannot parse domain %q", constraint)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(domainLabels) < len(constraintLabels) ||
|
|
||||||
(mustHaveSubdomains && len(domainLabels) == len(constraintLabels)) {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, constraintLabel := range constraintLabels {
|
|
||||||
if !strings.EqualFold(constraintLabel, domainLabels[i]) {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
146
smx509/x509.go
146
smx509/x509.go
@ -35,6 +35,8 @@ type pkixPublicKey struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ParsePKIXPublicKey parses a public key in PKIX, ASN.1 DER form.
|
// ParsePKIXPublicKey parses a public key in PKIX, ASN.1 DER form.
|
||||||
|
// The encoded public key is a SubjectPublicKeyInfo structure
|
||||||
|
// (see RFC 5280, Section 4.1).
|
||||||
//
|
//
|
||||||
// It returns a *rsa.PublicKey, *dsa.PublicKey, *ecdsa.PublicKey, or
|
// It returns a *rsa.PublicKey, *dsa.PublicKey, *ecdsa.PublicKey, or
|
||||||
// ed25519.PublicKey. More types might be supported in the future.
|
// ed25519.PublicKey. More types might be supported in the future.
|
||||||
@ -119,6 +121,8 @@ func marshalPublicKey(pub interface{}) (publicKeyBytes []byte, publicKeyAlgorith
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MarshalPKIXPublicKey converts a public key to PKIX, ASN.1 DER form.
|
// MarshalPKIXPublicKey converts a public key to PKIX, ASN.1 DER form.
|
||||||
|
// The encoded public key is a SubjectPublicKeyInfo structure
|
||||||
|
// (see RFC 5280, Section 4.1).
|
||||||
//
|
//
|
||||||
// The following key types are currently supported: *rsa.PublicKey, *ecdsa.PublicKey
|
// The following key types are currently supported: *rsa.PublicKey, *ecdsa.PublicKey
|
||||||
// and ed25519.PublicKey. Unsupported key types result in an error.
|
// and ed25519.PublicKey. Unsupported key types result in an error.
|
||||||
@ -145,14 +149,8 @@ func MarshalPKIXPublicKey(pub interface{}) ([]byte, error) {
|
|||||||
return ret, nil
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CertificateRequest represents a PKCS #10, certificate signature request.
|
|
||||||
type CertificateRequest x509.CertificateRequest
|
|
||||||
|
|
||||||
func (c *CertificateRequest) asX509() *x509.CertificateRequest {
|
|
||||||
return (*x509.CertificateRequest)(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
// These structures reflect the ASN.1 structure of X.509 certificates.:
|
// These structures reflect the ASN.1 structure of X.509 certificates.:
|
||||||
|
|
||||||
type certificate struct {
|
type certificate struct {
|
||||||
Raw asn1.RawContent
|
Raw asn1.RawContent
|
||||||
TBSCertificate tbsCertificate
|
TBSCertificate tbsCertificate
|
||||||
@ -238,11 +236,42 @@ const (
|
|||||||
Ed25519 = x509.Ed25519
|
Ed25519 = x509.Ed25519
|
||||||
)
|
)
|
||||||
|
|
||||||
// pkcs1PublicKey reflects the ASN.1 structure of a PKCS#1 public key.
|
// OIDs for signature algorithms
|
||||||
type pkcs1PublicKey struct {
|
var (
|
||||||
N *big.Int
|
oidSignatureMD2WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 2}
|
||||||
E int
|
oidSignatureMD5WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 4}
|
||||||
}
|
oidSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5}
|
||||||
|
oidSignatureSHA256WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11}
|
||||||
|
oidSignatureSHA384WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 12}
|
||||||
|
oidSignatureSHA512WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 13}
|
||||||
|
oidSignatureRSAPSS = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 10}
|
||||||
|
oidSignatureDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 3}
|
||||||
|
oidSignatureDSAWithSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 2}
|
||||||
|
oidSignatureECDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 1}
|
||||||
|
oidSignatureECDSAWithSHA256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 2}
|
||||||
|
oidSignatureECDSAWithSHA384 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 3}
|
||||||
|
oidSignatureECDSAWithSHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4}
|
||||||
|
oidSignatureEd25519 = asn1.ObjectIdentifier{1, 3, 101, 112}
|
||||||
|
|
||||||
|
oidSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 1}
|
||||||
|
oidSHA384 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 2}
|
||||||
|
oidSHA512 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 3}
|
||||||
|
|
||||||
|
oidMGF1 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 8}
|
||||||
|
|
||||||
|
// oidISOSignatureSHA1WithRSA means the same as oidSignatureSHA1WithRSA
|
||||||
|
// but it's specified by ISO. Microsoft's makecert.exe has been known
|
||||||
|
// to produce certificates with this OID.
|
||||||
|
oidISOSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 29}
|
||||||
|
|
||||||
|
// GB/T 33560-2017 信息安全技术 密码应用标识规范
|
||||||
|
// 附录A(规范性附录)商用密码领域中的相关OID定义
|
||||||
|
//
|
||||||
|
// http://gmssl.org/docs/oid.html
|
||||||
|
oidSignatureSM2WithSM3 = asn1.ObjectIdentifier{1, 2, 156, 10197, 1, 501}
|
||||||
|
oidSignatureSM2WithSHA1 = asn1.ObjectIdentifier{1, 2, 156, 10197, 1, 502}
|
||||||
|
oidSignatureSM2WithSHA256 = asn1.ObjectIdentifier{1, 2, 156, 10197, 1, 503}
|
||||||
|
)
|
||||||
|
|
||||||
var signatureAlgorithmDetails = []struct {
|
var signatureAlgorithmDetails = []struct {
|
||||||
algo SignatureAlgorithm
|
algo SignatureAlgorithm
|
||||||
@ -370,7 +399,7 @@ var (
|
|||||||
oidPublicKeyRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
|
oidPublicKeyRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
|
||||||
oidPublicKeyDSA = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 1}
|
oidPublicKeyDSA = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 1}
|
||||||
oidPublicKeyECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1}
|
oidPublicKeyECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1}
|
||||||
oidPublicKeyEd25519 = asn1.ObjectIdentifier{1, 3, 101, 112}
|
oidPublicKeyEd25519 = oidSignatureEd25519
|
||||||
)
|
)
|
||||||
|
|
||||||
func getPublicKeyAlgorithmFromOID(oid asn1.ObjectIdentifier) PublicKeyAlgorithm {
|
func getPublicKeyAlgorithmFromOID(oid asn1.ObjectIdentifier) PublicKeyAlgorithm {
|
||||||
@ -387,44 +416,36 @@ func getPublicKeyAlgorithmFromOID(oid asn1.ObjectIdentifier) PublicKeyAlgorithm
|
|||||||
return UnknownPublicKeyAlgorithm
|
return UnknownPublicKeyAlgorithm
|
||||||
}
|
}
|
||||||
|
|
||||||
// http://gmssl.org/docs/oid.html
|
// RFC 5480, 2.1.1.1. Named Curve
|
||||||
var (
|
var (
|
||||||
oidNamedCurveP224 = asn1.ObjectIdentifier{1, 3, 132, 0, 33}
|
oidNamedCurveP224 = asn1.ObjectIdentifier{1, 3, 132, 0, 33}
|
||||||
oidNamedCurveP256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 7}
|
oidNamedCurveP256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 7}
|
||||||
oidNamedCurveP384 = asn1.ObjectIdentifier{1, 3, 132, 0, 34}
|
oidNamedCurveP384 = asn1.ObjectIdentifier{1, 3, 132, 0, 34}
|
||||||
oidNamedCurveP521 = asn1.ObjectIdentifier{1, 3, 132, 0, 35}
|
oidNamedCurveP521 = asn1.ObjectIdentifier{1, 3, 132, 0, 35}
|
||||||
|
|
||||||
|
// GB/T 33560-2017 信息安全技术 密码应用标识规范
|
||||||
|
// 附录A(规范性附录)商用密码领域中的相关OID定义
|
||||||
|
//
|
||||||
|
// http://gmssl.org/docs/oid.html
|
||||||
oidNamedCurveP256SM2 = asn1.ObjectIdentifier{1, 2, 156, 10197, 1, 301}
|
oidNamedCurveP256SM2 = asn1.ObjectIdentifier{1, 2, 156, 10197, 1, 301}
|
||||||
|
|
||||||
oidSignatureMD2WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 2}
|
|
||||||
oidSignatureMD5WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 4}
|
|
||||||
oidSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5}
|
|
||||||
oidSignatureSHA256WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11}
|
|
||||||
oidSignatureSHA384WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 12}
|
|
||||||
oidSignatureSHA512WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 13}
|
|
||||||
oidSignatureRSAPSS = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 10}
|
|
||||||
oidSignatureDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 3}
|
|
||||||
oidSignatureDSAWithSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 2}
|
|
||||||
oidSignatureECDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 1}
|
|
||||||
oidSignatureECDSAWithSHA256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 2}
|
|
||||||
oidSignatureECDSAWithSHA384 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 3}
|
|
||||||
oidSignatureECDSAWithSHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4}
|
|
||||||
oidSignatureEd25519 = asn1.ObjectIdentifier{1, 3, 101, 112}
|
|
||||||
oidSignatureSM2WithSM3 = asn1.ObjectIdentifier{1, 2, 156, 10197, 1, 501}
|
|
||||||
oidSignatureSM2WithSHA1 = asn1.ObjectIdentifier{1, 2, 156, 10197, 1, 502}
|
|
||||||
oidSignatureSM2WithSHA256 = asn1.ObjectIdentifier{1, 2, 156, 10197, 1, 503}
|
|
||||||
|
|
||||||
oidSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 1}
|
|
||||||
oidSHA384 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 2}
|
|
||||||
oidSHA512 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 3}
|
|
||||||
|
|
||||||
oidMGF1 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 8}
|
|
||||||
|
|
||||||
// oidISOSignatureSHA1WithRSA means the same as oidSignatureSHA1WithRSA
|
|
||||||
// but it's specified by ISO. Microsoft's makecert.exe has been known
|
|
||||||
// to produce certificates with this OID.
|
|
||||||
oidISOSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 29}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func namedCurveFromOID(oid asn1.ObjectIdentifier) elliptic.Curve {
|
||||||
|
switch {
|
||||||
|
case oid.Equal(oidNamedCurveP224):
|
||||||
|
return elliptic.P224()
|
||||||
|
case oid.Equal(oidNamedCurveP256):
|
||||||
|
return elliptic.P256()
|
||||||
|
case oid.Equal(oidNamedCurveP384):
|
||||||
|
return elliptic.P384()
|
||||||
|
case oid.Equal(oidNamedCurveP521):
|
||||||
|
return elliptic.P521()
|
||||||
|
case oid.Equal(oidNamedCurveP256SM2):
|
||||||
|
return sm2.P256()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func oidFromNamedCurve(curve elliptic.Curve) (asn1.ObjectIdentifier, bool) {
|
func oidFromNamedCurve(curve elliptic.Curve) (asn1.ObjectIdentifier, bool) {
|
||||||
switch curve {
|
switch curve {
|
||||||
case elliptic.P224():
|
case elliptic.P224():
|
||||||
@ -442,22 +463,6 @@ func oidFromNamedCurve(curve elliptic.Curve) (asn1.ObjectIdentifier, bool) {
|
|||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func namedCurveFromOID(oid asn1.ObjectIdentifier) elliptic.Curve {
|
|
||||||
switch {
|
|
||||||
case oid.Equal(oidNamedCurveP224):
|
|
||||||
return elliptic.P224()
|
|
||||||
case oid.Equal(oidNamedCurveP256):
|
|
||||||
return elliptic.P256()
|
|
||||||
case oid.Equal(oidNamedCurveP384):
|
|
||||||
return elliptic.P384()
|
|
||||||
case oid.Equal(oidNamedCurveP521):
|
|
||||||
return elliptic.P521()
|
|
||||||
case oid.Equal(oidNamedCurveP256SM2):
|
|
||||||
return sm2.P256()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// KeyUsage represents the set of actions that are valid for a given key. It's
|
// KeyUsage represents the set of actions that are valid for a given key. It's
|
||||||
// a bitmap of the KeyUsage* constants.
|
// a bitmap of the KeyUsage* constants.
|
||||||
type KeyUsage = x509.KeyUsage
|
type KeyUsage = x509.KeyUsage
|
||||||
@ -838,7 +843,7 @@ func marshalSANs(dnsNames, emailAddresses []string, ipAddresses []net.IP, uris [
|
|||||||
if err := isIA5String(uriStr); err != nil {
|
if err := isIA5String(uriStr); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeURI, Class: 2, Bytes: []byte(uri.String())})
|
rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeURI, Class: 2, Bytes: []byte(uriStr)})
|
||||||
}
|
}
|
||||||
return asn1.Marshal(rawValues)
|
return asn1.Marshal(rawValues)
|
||||||
}
|
}
|
||||||
@ -1256,7 +1261,7 @@ func signingParamsForPublicKey(pub interface{}, requestedSigAlgo SignatureAlgori
|
|||||||
var emptyASN1Subject = []byte{0x30, 0}
|
var emptyASN1Subject = []byte{0x30, 0}
|
||||||
|
|
||||||
// CreateCertificate creates a new X.509 v3 certificate based on a template.
|
// CreateCertificate creates a new X.509 v3 certificate based on a template.
|
||||||
// The following members of template are used:
|
// The following members of template are currently used:
|
||||||
//
|
//
|
||||||
// - AuthorityKeyId
|
// - AuthorityKeyId
|
||||||
// - BasicConstraintsValid
|
// - BasicConstraintsValid
|
||||||
@ -1293,7 +1298,7 @@ var emptyASN1Subject = []byte{0x30, 0}
|
|||||||
//
|
//
|
||||||
// The certificate is signed by parent. If parent is equal to template then the
|
// The certificate is signed by parent. If parent is equal to template then the
|
||||||
// certificate is self-signed. The parameter pub is the public key of the
|
// certificate is self-signed. The parameter pub is the public key of the
|
||||||
// signee and priv is the private key of the signer.
|
// certificate to be generated and priv is the private key of the signer.
|
||||||
//
|
//
|
||||||
// The returned slice is the certificate in DER encoding.
|
// The returned slice is the certificate in DER encoding.
|
||||||
//
|
//
|
||||||
@ -1304,6 +1309,9 @@ var emptyASN1Subject = []byte{0x30, 0}
|
|||||||
// The AuthorityKeyId will be taken from the SubjectKeyId of parent, if any,
|
// The AuthorityKeyId will be taken from the SubjectKeyId of parent, if any,
|
||||||
// unless the resulting certificate is self-signed. Otherwise the value from
|
// unless the resulting certificate is self-signed. Otherwise the value from
|
||||||
// template will be used.
|
// template will be used.
|
||||||
|
//
|
||||||
|
// If SubjectKeyId from template is empty and the template is a CA, SubjectKeyId
|
||||||
|
// will be generated from the hash of the public key.
|
||||||
func CreateCertificate(rand io.Reader, template, parent *x509.Certificate, pub, priv interface{}) ([]byte, error) {
|
func CreateCertificate(rand io.Reader, template, parent *x509.Certificate, pub, priv interface{}) ([]byte, error) {
|
||||||
key, ok := priv.(crypto.Signer)
|
key, ok := priv.(crypto.Signer)
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -1395,6 +1403,7 @@ func CreateCertificate(rand io.Reader, template, parent *x509.Certificate, pub,
|
|||||||
h.Write(signed)
|
h.Write(signed)
|
||||||
signed = h.Sum(nil)
|
signed = h.Sum(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
var signerOpts crypto.SignerOpts = hashFunc
|
var signerOpts crypto.SignerOpts = hashFunc
|
||||||
if template.SignatureAlgorithm != 0 && isRSAPSS(template.SignatureAlgorithm) {
|
if template.SignatureAlgorithm != 0 && isRSAPSS(template.SignatureAlgorithm) {
|
||||||
signerOpts = &rsa.PSSOptions{
|
signerOpts = &rsa.PSSOptions{
|
||||||
@ -1449,6 +1458,9 @@ func ParseDERCRL(derBytes []byte) (*pkix.CertificateList, error) {
|
|||||||
|
|
||||||
// CreateCRL returns a DER encoded CRL, signed by this Certificate, that
|
// CreateCRL returns a DER encoded CRL, signed by this Certificate, that
|
||||||
// contains the given list of revoked certificates.
|
// contains the given list of revoked certificates.
|
||||||
|
//
|
||||||
|
// Note: this method does not generate an RFC 5280 conformant X.509 v2 CRL.
|
||||||
|
// To generate a standards compliant CRL, use CreateRevocationList instead.
|
||||||
func (c *Certificate) CreateCRL(rand io.Reader, priv interface{}, revokedCerts []pkix.RevokedCertificate, now, expiry time.Time) (crlBytes []byte, err error) {
|
func (c *Certificate) CreateCRL(rand io.Reader, priv interface{}, revokedCerts []pkix.RevokedCertificate, now, expiry time.Time) (crlBytes []byte, err error) {
|
||||||
key, ok := priv.(crypto.Signer)
|
key, ok := priv.(crypto.Signer)
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -1514,6 +1526,13 @@ func (c *Certificate) CreateCRL(rand io.Reader, priv interface{}, revokedCerts [
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CertificateRequest represents a PKCS #10, certificate signature request.
|
||||||
|
type CertificateRequest x509.CertificateRequest
|
||||||
|
|
||||||
|
func (c *CertificateRequest) asX509() *x509.CertificateRequest {
|
||||||
|
return (*x509.CertificateRequest)(c)
|
||||||
|
}
|
||||||
|
|
||||||
// These structures reflect the ASN.1 structure of X.509 certificate
|
// These structures reflect the ASN.1 structure of X.509 certificate
|
||||||
// signature requests (see RFC 2986):
|
// signature requests (see RFC 2986):
|
||||||
|
|
||||||
@ -1532,7 +1551,7 @@ type certificateRequest struct {
|
|||||||
SignatureValue asn1.BitString
|
SignatureValue asn1.BitString
|
||||||
}
|
}
|
||||||
|
|
||||||
// oidExtensionRequest is a PKCS#9 OBJECT IDENTIFIER that indicates requested
|
// oidExtensionRequest is a PKCS #9 OBJECT IDENTIFIER that indicates requested
|
||||||
// extensions in a CSR.
|
// extensions in a CSR.
|
||||||
var oidExtensionRequest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 14}
|
var oidExtensionRequest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 14}
|
||||||
|
|
||||||
@ -1624,6 +1643,7 @@ func CreateCertificateRequest(rand io.Reader, template *x509.CertificateRequest,
|
|||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("x509: certificate private key does not implement crypto.Signer")
|
return nil, errors.New("x509: certificate private key does not implement crypto.Signer")
|
||||||
}
|
}
|
||||||
|
|
||||||
var hashFunc crypto.Hash
|
var hashFunc crypto.Hash
|
||||||
var sigAlgo pkix.AlgorithmIdentifier
|
var sigAlgo pkix.AlgorithmIdentifier
|
||||||
hashFunc, sigAlgo, err = signingParamsForPublicKey(key.Public(), template.SignatureAlgorithm)
|
hashFunc, sigAlgo, err = signingParamsForPublicKey(key.Public(), template.SignatureAlgorithm)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user