sec/sign.go (297 lines of code) (raw):

/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 sec import ( "bytes" "crypto" "crypto/ecdsa" "crypto/rsa" "crypto/x509" "crypto/x509/pkix" "encoding/asn1" "encoding/pem" "github.com/apache/mynewt-artifact/errors" "golang.org/x/crypto/ed25519" ) type SigType int const ( SIG_TYPE_RSA2048 SigType = iota SIG_TYPE_RSA3072 SIG_TYPE_ECDSA224 SIG_TYPE_ECDSA256 SIG_TYPE_ED25519 ) var sigTypeNameMap = map[SigType]string{ SIG_TYPE_RSA2048: "rsa2048", SIG_TYPE_ECDSA224: "ecdsa224", SIG_TYPE_ECDSA256: "ecdsa256", SIG_TYPE_RSA3072: "rsa3072", SIG_TYPE_ED25519: "ed25519", } type PrivSignKey struct { // Only one of these members is non-nil. Rsa *rsa.PrivateKey Ec *ecdsa.PrivateKey Ed25519 *ed25519.PrivateKey } type PubSignKey struct { Rsa *rsa.PublicKey Ec *ecdsa.PublicKey Ed25519 ed25519.PublicKey } type Sig struct { Type SigType KeyHash []byte Data []byte } var oidPrivateKeyEd25519 = asn1.ObjectIdentifier{1, 3, 101, 112} func SigTypeString(typ SigType) string { s := sigTypeNameMap[typ] if s == "" { return "unknown" } else { return s } } func SigStringType(s string) (SigType, error) { for k, v := range sigTypeNameMap { if s == v { return k, nil } } return 0, errors.Errorf("unknown sig type name: \"%s\"", s) } func parsePrivSignKeyItf(keyBytes []byte) (interface{}, error) { var privKey interface{} var err error block, data := pem.Decode(keyBytes) if block != nil && block.Type == "EC PARAMETERS" { /* * Openssl prepends an EC PARAMETERS block before the * key itself. If we see this first, just skip it, * and go on to the data block. */ block, _ = pem.Decode(data) } if block != nil && block.Type == "RSA PRIVATE KEY" { /* * ParsePKCS1PrivateKey returns an RSA private key from its ASN.1 * PKCS#1 DER encoded form. */ privKey, err = x509.ParsePKCS1PrivateKey(block.Bytes) if err != nil { return nil, errors.Wrapf(err, "Priv key parsing failed") } } if block != nil && block.Type == "EC PRIVATE KEY" { /* * ParseECPrivateKey returns a EC private key */ privKey, err = x509.ParseECPrivateKey(block.Bytes) if err != nil { return nil, errors.Wrapf(err, "Priv key parsing failed") } } if block != nil && block.Type == "PRIVATE KEY" { // This indicates a PKCS#8 unencrypted private key. // The particular type of key will be indicated within // the key itself. privKey, err = x509.ParsePKCS8PrivateKey(block.Bytes) } if block != nil && block.Type == "ENCRYPTED PRIVATE KEY" { // This indicates a PKCS#8 key wrapped with PKCS#5 // encryption. privKey, err = parseEncryptedPrivateKey(block.Bytes) if err != nil { return nil, errors.Wrapf( err, "Unable to decode encrypted private key") } } if privKey == nil { return nil, errors.Errorf( "Unknown private key format, EC/RSA private " + "key in PEM format only.") } return privKey, nil } func ParsePubSignKey(keyBytes []byte) (PubSignKey, error) { key := PubSignKey{} itf, err := parsePubPemKey(keyBytes) if err != nil { return key, err } switch pub := itf.(type) { case *rsa.PublicKey: key.Rsa = pub case *ecdsa.PublicKey: key.Ec = pub case ed25519.PublicKey: key.Ed25519 = pub default: return key, errors.Errorf("unknown public signing key type: %T", pub) } return key, nil } func ParsePrivSignKey(keyBytes []byte) (PrivSignKey, error) { key := PrivSignKey{} itf, err := parsePrivSignKeyItf(keyBytes) if err != nil { return key, err } switch priv := itf.(type) { case *rsa.PrivateKey: key.Rsa = priv case *ecdsa.PrivateKey: key.Ec = priv case ed25519.PrivateKey: key.Ed25519 = &priv default: return key, errors.Errorf("unknown private key type: %T", itf) } return key, nil } func (key *PrivSignKey) AssertValid() { if key.Rsa == nil && key.Ec == nil && key.Ed25519 == nil { panic("invalid key; neither RSA nor ECC nor ED25519") } } func (key *PrivSignKey) PubKey() PubSignKey { key.AssertValid() if key.Rsa != nil { return PubSignKey{Rsa: &key.Rsa.PublicKey} } else if key.Ec != nil { return PubSignKey{Ec: &key.Ec.PublicKey} } else { x := PubSignKey{Ed25519: key.Ed25519.Public().(ed25519.PublicKey)} return x } } func (key *PrivSignKey) PubBytes() ([]byte, error) { pk := key.PubKey() return pk.Bytes() } func (key *PrivSignKey) SigLen() uint16 { key.AssertValid() if key.Rsa != nil { pubk := key.Rsa.Public().(*rsa.PublicKey) return uint16(pubk.Size()) } else if key.Ec != nil { switch key.Ec.Curve.Params().Name { case "P-224": return 68 case "P-256": return 72 default: return 0 } } else { return ed25519.SignatureSize } } func (key *PubSignKey) AssertValid() { if key.Rsa == nil && key.Ec == nil && key.Ed25519 == nil { panic("invalid public key; neither RSA nor ECC nor ED25519") } if key.Ed25519 != nil { if _, err := marshalEd25519(key.Ed25519); err != nil { panic("invalid public ed25519 key") } } } type pkixPublicKey struct { Algo pkix.AlgorithmIdentifier BitString asn1.BitString } func marshalEd25519(pubbytes []uint8) ([]uint8, error) { pkix := pkixPublicKey{ Algo: pkix.AlgorithmIdentifier{ Algorithm: oidPrivateKeyEd25519, }, BitString: asn1.BitString{ Bytes: pubbytes, BitLength: 8 * len(pubbytes), }, } ret, err := asn1.Marshal(pkix) if err != nil { return nil, errors.Wrapf(err, "failed to encode ed25519 public key") } return ret, nil } func unmarshalEd25519(pubbytes []uint8) (pkixPublicKey, error) { var pkix pkixPublicKey if _, err := asn1.Unmarshal(pubbytes, &pkix); err != nil { return pkix, errors.Wrapf(err, "failed to parse ed25519 public key") } return pkix, nil } func (key *PubSignKey) Bytes() ([]byte, error) { key.AssertValid() var b []byte var err error typ, err := key.SigType() if err != nil { return nil, err } switch typ { case SIG_TYPE_RSA2048, SIG_TYPE_RSA3072: b, err = asn1.Marshal(*key.Rsa) case SIG_TYPE_ECDSA224, SIG_TYPE_ECDSA256: b, err = x509.MarshalPKIXPublicKey(key.Ec) case SIG_TYPE_ED25519: b, err = marshalEd25519([]byte(key.Ed25519)) default: err = errors.Errorf("unknown sig type: %v", typ) } if err != nil { return nil, err } return b, nil } func (key *PubSignKey) SigType() (SigType, error) { if key.Rsa != nil { switch key.Rsa.Size() { case 2048 / 8: return SIG_TYPE_RSA2048, nil case 3072 / 8: return SIG_TYPE_RSA3072, nil default: return 0, errors.Errorf("unknown RSA key size (bytes): %d", key.Rsa.Size()) } } else if key.Ec != nil { switch key.Ec.Curve.Params().Name { case "P-224": return SIG_TYPE_ECDSA224, nil case "P-256": return SIG_TYPE_ECDSA256, nil default: return 0, errors.Errorf("unknown EC curve: %s", key.Ec.Curve.Params().Name) } } else if key.Ed25519 != nil { return SIG_TYPE_ED25519, nil } return 0, errors.Errorf("invalid key: no non-nil members") } func (key *PubSignKey) Hash() ([]byte, error) { pubBytes, err := key.Bytes() if err != nil { return nil, errors.WithStack(err) } return RawKeyHash(pubBytes), nil } func checkOneKeyOneSig(k PubSignKey, sig Sig, hash []byte) (bool, error) { keyHash, err := k.Hash() if err != nil { return false, err } if !bytes.Equal(keyHash, sig.KeyHash) { return false, nil } if k.Rsa != nil { opts := rsa.PSSOptions{ SaltLength: rsa.PSSSaltLengthEqualsHash, } err := rsa.VerifyPSS(k.Rsa, crypto.SHA256, hash, sig.Data, &opts) return err == nil, nil } if k.Ec != nil { return false, errors.Errorf( "ecdsa signature verification not supported") } if k.Ed25519 != nil { return ed25519.Verify(k.Ed25519, hash, sig.Data), nil } return false, nil } func VerifySigs(key PubSignKey, sigs []Sig, hash []byte) (int, error) { for i, s := range sigs { match, err := checkOneKeyOneSig(key, s, hash) if err != nil { return -1, err } if match { return i, nil } } return -1, nil }