...

Source file src/github.com/ThalesIgnite/crypto11/ecdsa.go

Documentation: github.com/ThalesIgnite/crypto11

     1  // Copyright 2016, 2017 Thales e-Security, Inc
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining
     4  // a copy of this software and associated documentation files (the
     5  // "Software"), to deal in the Software without restriction, including
     6  // without limitation the rights to use, copy, modify, merge, publish,
     7  // distribute, sublicense, and/or sell copies of the Software, and to
     8  // permit persons to whom the Software is furnished to do so, subject to
     9  // the following conditions:
    10  //
    11  // The above copyright notice and this permission notice shall be
    12  // included in all copies or substantial portions of the Software.
    13  //
    14  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    15  // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    16  // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    17  // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
    18  // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    19  // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
    20  // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    21  
    22  package crypto11
    23  
    24  import (
    25  	"bytes"
    26  	"crypto"
    27  	"crypto/ecdsa"
    28  	"crypto/elliptic"
    29  	"encoding/asn1"
    30  	"io"
    31  	"math/big"
    32  
    33  	"github.com/miekg/pkcs11"
    34  	"github.com/pkg/errors"
    35  )
    36  
    37  // errUnsupportedEllipticCurve is returned when an elliptic curve
    38  // unsupported by crypto11 is specified.  Note that the error behavior
    39  // for an elliptic curve unsupported by the underlying PKCS#11
    40  // implementation will be different.
    41  var errUnsupportedEllipticCurve = errors.New("unsupported elliptic curve")
    42  
    43  // pkcs11PrivateKeyECDSA contains a reference to a loaded PKCS#11 ECDSA private key object.
    44  type pkcs11PrivateKeyECDSA struct {
    45  	pkcs11PrivateKey
    46  }
    47  
    48  // Information about an Elliptic Curve
    49  type curveInfo struct {
    50  	// ASN.1 marshaled OID
    51  	oid []byte
    52  
    53  	// Curve definition in Go form
    54  	curve elliptic.Curve
    55  }
    56  
    57  // ASN.1 marshal some value and panic on error
    58  func mustMarshal(val interface{}) []byte {
    59  	if b, err := asn1.Marshal(val); err != nil {
    60  		panic(err)
    61  	} else {
    62  		return b
    63  	}
    64  }
    65  
    66  // Note: some of these are outside what crypto/elliptic currently
    67  // knows about. So I'm making a (reasonable) assumption about what
    68  // they will be called if they are either added or if someone
    69  // specifies them explicitly.
    70  //
    71  // For public key export, the curve has to be a known one, otherwise
    72  // you're stuffed. This is probably better fixed by adding well-known
    73  // curves to crypto/elliptic rather than having a private copy here.
    74  var wellKnownCurves = map[string]curveInfo{
    75  	"P-192": {
    76  		mustMarshal(asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 1}),
    77  		nil,
    78  	},
    79  	"P-224": {
    80  		mustMarshal(asn1.ObjectIdentifier{1, 3, 132, 0, 33}),
    81  		elliptic.P224(),
    82  	},
    83  	"P-256": {
    84  		mustMarshal(asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 7}),
    85  		elliptic.P256(),
    86  	},
    87  	"P-384": {
    88  		mustMarshal(asn1.ObjectIdentifier{1, 3, 132, 0, 34}),
    89  		elliptic.P384(),
    90  	},
    91  	"P-521": {
    92  		mustMarshal(asn1.ObjectIdentifier{1, 3, 132, 0, 35}),
    93  		elliptic.P521(),
    94  	},
    95  
    96  	"K-163": {
    97  		mustMarshal(asn1.ObjectIdentifier{1, 3, 132, 0, 1}),
    98  		nil,
    99  	},
   100  	"K-233": {
   101  		mustMarshal(asn1.ObjectIdentifier{1, 3, 132, 0, 26}),
   102  		nil,
   103  	},
   104  	"K-283": {
   105  		mustMarshal(asn1.ObjectIdentifier{1, 3, 132, 0, 16}),
   106  		nil,
   107  	},
   108  	"K-409": {
   109  		mustMarshal(asn1.ObjectIdentifier{1, 3, 132, 0, 36}),
   110  		nil,
   111  	},
   112  	"K-571": {
   113  		mustMarshal(asn1.ObjectIdentifier{1, 3, 132, 0, 38}),
   114  		nil,
   115  	},
   116  
   117  	"B-163": {
   118  		mustMarshal(asn1.ObjectIdentifier{1, 3, 132, 0, 15}),
   119  		nil,
   120  	},
   121  	"B-233": {
   122  		mustMarshal(asn1.ObjectIdentifier{1, 3, 132, 0, 27}),
   123  		nil,
   124  	},
   125  	"B-283": {
   126  		mustMarshal(asn1.ObjectIdentifier{1, 3, 132, 0, 17}),
   127  		nil,
   128  	},
   129  	"B-409": {
   130  		mustMarshal(asn1.ObjectIdentifier{1, 3, 132, 0, 37}),
   131  		nil,
   132  	},
   133  	"B-571": {
   134  		mustMarshal(asn1.ObjectIdentifier{1, 3, 132, 0, 39}),
   135  		nil,
   136  	},
   137  }
   138  
   139  func marshalEcParams(c elliptic.Curve) ([]byte, error) {
   140  	if ci, ok := wellKnownCurves[c.Params().Name]; ok {
   141  		return ci.oid, nil
   142  	}
   143  	// TODO use ANSI X9.62 ECParameters representation instead
   144  	return nil, errUnsupportedEllipticCurve
   145  }
   146  
   147  func unmarshalEcParams(b []byte) (elliptic.Curve, error) {
   148  	// See if it's a well-known curve
   149  	for _, ci := range wellKnownCurves {
   150  		if bytes.Equal(b, ci.oid) {
   151  			if ci.curve != nil {
   152  				return ci.curve, nil
   153  			}
   154  			return nil, errUnsupportedEllipticCurve
   155  		}
   156  	}
   157  	// TODO try ANSI X9.62 ECParameters representation
   158  	return nil, errUnsupportedEllipticCurve
   159  }
   160  
   161  func unmarshalEcPoint(b []byte, c elliptic.Curve) (*big.Int, *big.Int, error) {
   162  	var pointBytes []byte
   163  	extra, err := asn1.Unmarshal(b, &pointBytes)
   164  	if err != nil {
   165  		return nil, nil, errors.WithMessage(err, "elliptic curve point is invalid ASN.1")
   166  	}
   167  
   168  	if len(extra) > 0 {
   169  		// We weren't expecting extra data
   170  		return nil, nil, errors.New("unexpected data found when parsing elliptic curve point")
   171  	}
   172  
   173  	x, y := elliptic.Unmarshal(c, pointBytes)
   174  	if x == nil || y == nil {
   175  		return nil, nil, errors.New("failed to parse elliptic curve point")
   176  	}
   177  	return x, y, nil
   178  }
   179  
   180  // Export the public key corresponding to a private ECDSA key.
   181  func exportECDSAPublicKey(session *pkcs11Session, pubHandle pkcs11.ObjectHandle) (crypto.PublicKey, error) {
   182  	var err error
   183  	var attributes []*pkcs11.Attribute
   184  	var pub ecdsa.PublicKey
   185  	template := []*pkcs11.Attribute{
   186  		pkcs11.NewAttribute(pkcs11.CKA_ECDSA_PARAMS, nil),
   187  		pkcs11.NewAttribute(pkcs11.CKA_EC_POINT, nil),
   188  	}
   189  	if attributes, err = session.ctx.GetAttributeValue(session.handle, pubHandle, template); err != nil {
   190  		return nil, err
   191  	}
   192  	if pub.Curve, err = unmarshalEcParams(attributes[0].Value); err != nil {
   193  		return nil, err
   194  	}
   195  	if pub.X, pub.Y, err = unmarshalEcPoint(attributes[1].Value, pub.Curve); err != nil {
   196  		return nil, err
   197  	}
   198  	return &pub, nil
   199  }
   200  
   201  // GenerateECDSAKeyPair creates a ECDSA key pair on the token using curve c. The id parameter is used to
   202  // set CKA_ID and must be non-nil. Only a limited set of named elliptic curves are supported. The
   203  // underlying PKCS#11 implementation may impose further restrictions.
   204  func (c *Context) GenerateECDSAKeyPair(id []byte, curve elliptic.Curve) (Signer, error) {
   205  	if c.closed.Get() {
   206  		return nil, errClosed
   207  	}
   208  
   209  	public, err := NewAttributeSetWithID(id)
   210  	if err != nil {
   211  		return nil, err
   212  	}
   213  	// Copy the AttributeSet to allow modifications.
   214  	private := public.Copy()
   215  
   216  	return c.GenerateECDSAKeyPairWithAttributes(public, private, curve)
   217  }
   218  
   219  // GenerateECDSAKeyPairWithLabel creates a ECDSA key pair on the token using curve c. The id and label parameters are used to
   220  // set CKA_ID and CKA_LABEL respectively and must be non-nil. Only a limited set of named elliptic curves are supported. The
   221  // underlying PKCS#11 implementation may impose further restrictions.
   222  func (c *Context) GenerateECDSAKeyPairWithLabel(id, label []byte, curve elliptic.Curve) (Signer, error) {
   223  	if c.closed.Get() {
   224  		return nil, errClosed
   225  	}
   226  
   227  	public, err := NewAttributeSetWithIDAndLabel(id, label)
   228  	if err != nil {
   229  		return nil, err
   230  	}
   231  	// Copy the AttributeSet to allow modifications.
   232  	private := public.Copy()
   233  
   234  	return c.GenerateECDSAKeyPairWithAttributes(public, private, curve)
   235  }
   236  
   237  // GenerateECDSAKeyPairWithAttributes generates an ECDSA key pair on the token. After this function returns, public and
   238  // private will contain the attributes applied to the key pair. If required attributes are missing, they will be set to
   239  // a default value.
   240  func (c *Context) GenerateECDSAKeyPairWithAttributes(public, private AttributeSet, curve elliptic.Curve) (Signer, error) {
   241  	if c.closed.Get() {
   242  		return nil, errClosed
   243  	}
   244  
   245  	var k Signer
   246  	err := c.withSession(func(session *pkcs11Session) error {
   247  
   248  		parameters, err := marshalEcParams(curve)
   249  		if err != nil {
   250  			return err
   251  		}
   252  		public.AddIfNotPresent([]*pkcs11.Attribute{
   253  			pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PUBLIC_KEY),
   254  			pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, pkcs11.CKK_ECDSA),
   255  			pkcs11.NewAttribute(pkcs11.CKA_TOKEN, true),
   256  			pkcs11.NewAttribute(pkcs11.CKA_VERIFY, true),
   257  			pkcs11.NewAttribute(pkcs11.CKA_ECDSA_PARAMS, parameters),
   258  		})
   259  		private.AddIfNotPresent([]*pkcs11.Attribute{
   260  			pkcs11.NewAttribute(pkcs11.CKA_TOKEN, true),
   261  			pkcs11.NewAttribute(pkcs11.CKA_SIGN, true),
   262  			pkcs11.NewAttribute(pkcs11.CKA_SENSITIVE, true),
   263  			pkcs11.NewAttribute(pkcs11.CKA_EXTRACTABLE, false),
   264  		})
   265  
   266  		mech := []*pkcs11.Mechanism{pkcs11.NewMechanism(pkcs11.CKM_ECDSA_KEY_PAIR_GEN, nil)}
   267  		pubHandle, privHandle, err := session.ctx.GenerateKeyPair(session.handle,
   268  			mech,
   269  			public.ToSlice(),
   270  			private.ToSlice())
   271  		if err != nil {
   272  			return err
   273  		}
   274  
   275  		pub, err := exportECDSAPublicKey(session, pubHandle)
   276  		if err != nil {
   277  			return err
   278  		}
   279  		k = &pkcs11PrivateKeyECDSA{
   280  			pkcs11PrivateKey: pkcs11PrivateKey{
   281  				pkcs11Object: pkcs11Object{
   282  					handle:  privHandle,
   283  					context: c,
   284  				},
   285  				pubKeyHandle: pubHandle,
   286  				pubKey:       pub,
   287  			}}
   288  		return nil
   289  	})
   290  	return k, err
   291  }
   292  
   293  // Sign signs a message using an ECDSA key.
   294  //
   295  // This completes the implemention of crypto.Signer for pkcs11PrivateKeyECDSA.
   296  //
   297  // PKCS#11 expects to pick its own random data where necessary for signatures, so the rand argument is ignored.
   298  //
   299  // The return value is a DER-encoded byteblock.
   300  func (signer *pkcs11PrivateKeyECDSA) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) {
   301  	return signer.context.dsaGeneric(signer.handle, pkcs11.CKM_ECDSA, digest)
   302  }
   303  

View as plain text