...

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

Documentation: github.com/ThalesIgnite/crypto11

     1  // Copyright 2019 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  	"crypto/tls"
    26  	"crypto/x509"
    27  	"encoding/asn1"
    28  	"math/big"
    29  
    30  	"github.com/miekg/pkcs11"
    31  	"github.com/pkg/errors"
    32  )
    33  
    34  // FindCertificate retrieves a previously imported certificate. Any combination of id, label
    35  // and serial can be provided. An error is return if all are nil.
    36  func findCertificate(session *pkcs11Session, id []byte, label []byte, serial *big.Int) (cert *x509.Certificate, err error) {
    37  
    38  	rawCertificate, err := findRawCertificate(session, id, label, serial)
    39  	if err != nil {
    40  		return nil, err
    41  	}
    42  
    43  	if rawCertificate != nil {
    44  		cert, err = x509.ParseCertificate(rawCertificate)
    45  		if err != nil {
    46  			return nil, err
    47  		}
    48  	}
    49  
    50  	return cert, err
    51  }
    52  
    53  func findRawCertificate(session *pkcs11Session, id []byte, label []byte, serial *big.Int) (rawCertificate []byte, err error) {
    54  	if id == nil && label == nil && serial == nil {
    55  		return nil, errors.New("id, label and serial cannot all be nil")
    56  	}
    57  
    58  	var template []*pkcs11.Attribute
    59  
    60  	if id != nil {
    61  		template = append(template, pkcs11.NewAttribute(pkcs11.CKA_ID, id))
    62  	}
    63  	if label != nil {
    64  		template = append(template, pkcs11.NewAttribute(pkcs11.CKA_LABEL, label))
    65  	}
    66  	if serial != nil {
    67  		derSerial, err := asn1.Marshal(serial)
    68  		if err != nil {
    69  			return nil, errors.WithMessage(err, "failed to encode serial")
    70  		}
    71  
    72  		template = append(template, pkcs11.NewAttribute(pkcs11.CKA_SERIAL_NUMBER, derSerial))
    73  	}
    74  
    75  	template = append(template, pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_CERTIFICATE))
    76  
    77  	if err = session.ctx.FindObjectsInit(session.handle, template); err != nil {
    78  		return nil, err
    79  	}
    80  	defer func() {
    81  		finalErr := session.ctx.FindObjectsFinal(session.handle)
    82  		if err == nil {
    83  			err = finalErr
    84  		}
    85  	}()
    86  
    87  	handles, _, err := session.ctx.FindObjects(session.handle, 1)
    88  	if err != nil {
    89  		return nil, err
    90  	}
    91  	if len(handles) == 0 {
    92  		return nil, nil
    93  	}
    94  
    95  	attributes := []*pkcs11.Attribute{
    96  		pkcs11.NewAttribute(pkcs11.CKA_VALUE, 0),
    97  	}
    98  
    99  	if attributes, err = session.ctx.GetAttributeValue(session.handle, handles[0], attributes); err != nil {
   100  		return nil, err
   101  	}
   102  
   103  	rawCertificate = attributes[0].Value
   104  
   105  	return
   106  }
   107  
   108  // FindCertificate retrieves a previously imported certificate. Any combination of id, label
   109  // and serial can be provided. An error is return if all are nil.
   110  func (c *Context) FindCertificate(id []byte, label []byte, serial *big.Int) (*x509.Certificate, error) {
   111  
   112  	if c.closed.Get() {
   113  		return nil, errClosed
   114  	}
   115  
   116  	var cert *x509.Certificate
   117  	err := c.withSession(func(session *pkcs11Session) (err error) {
   118  		cert, err = findCertificate(session, id, label, serial)
   119  		return err
   120  	})
   121  
   122  	return cert, err
   123  }
   124  
   125  func (c *Context) FindAllPairedCertificates() (certificates []tls.Certificate, err error) {
   126  	if c.closed.Get() {
   127  		return nil, errClosed
   128  	}
   129  
   130  	err = c.withSession(func(session *pkcs11Session) error {
   131  		// Add the private key class to the template to find the private half
   132  		privAttributes := AttributeSet{}
   133  		err = privAttributes.Set(CkaClass, pkcs11.CKO_PRIVATE_KEY)
   134  		if err != nil {
   135  			return err
   136  		}
   137  
   138  		privHandles, err := findKeysWithAttributes(session, privAttributes.ToSlice())
   139  		if err != nil {
   140  			return err
   141  		}
   142  
   143  		for _, privHandle := range privHandles {
   144  
   145  			privateKey, certificate, err := c.makeKeyPair(session, &privHandle)
   146  
   147  			if err == errNoCkaId || err == errNoPublicHalf {
   148  				continue
   149  			}
   150  
   151  			if err != nil {
   152  				return err
   153  			}
   154  
   155  			if certificate == nil {
   156  				continue
   157  			}
   158  
   159  			tlsCert := tls.Certificate{
   160  				Leaf:       certificate,
   161  				PrivateKey: privateKey,
   162  			}
   163  
   164  			tlsCert.Certificate = append(tlsCert.Certificate, certificate.Raw)
   165  			certificates = append(certificates, tlsCert)
   166  		}
   167  
   168  		return nil
   169  	})
   170  
   171  	if err != nil {
   172  		return nil, err
   173  	}
   174  
   175  	return
   176  }
   177  
   178  // ImportCertificate imports a certificate onto the token. The id parameter is used to
   179  // set CKA_ID and must be non-nil.
   180  func (c *Context) ImportCertificate(id []byte, certificate *x509.Certificate) error {
   181  	if c.closed.Get() {
   182  		return errClosed
   183  	}
   184  
   185  	if err := notNilBytes(id, "id"); err != nil {
   186  		return err
   187  	}
   188  
   189  	template, err := NewAttributeSetWithID(id)
   190  	if err != nil {
   191  		return err
   192  	}
   193  	return c.ImportCertificateWithAttributes(template, certificate)
   194  }
   195  
   196  // ImportCertificateWithLabel imports a certificate onto the token.  The id and label parameters are used to
   197  // set CKA_ID and CKA_LABEL respectively and must be non-nil.
   198  func (c *Context) ImportCertificateWithLabel(id []byte, label []byte, certificate *x509.Certificate) error {
   199  	if c.closed.Get() {
   200  		return errClosed
   201  	}
   202  
   203  	if err := notNilBytes(id, "id"); err != nil {
   204  		return err
   205  	}
   206  	if err := notNilBytes(label, "label"); err != nil {
   207  		return err
   208  	}
   209  
   210  	template, err := NewAttributeSetWithIDAndLabel(id, label)
   211  	if err != nil {
   212  		return err
   213  	}
   214  	return c.ImportCertificateWithAttributes(template, certificate)
   215  }
   216  
   217  // ImportCertificateWithAttributes imports a certificate onto the token. After this function returns, template
   218  // will contain the attributes applied to the certificate. If required attributes are missing, they will be set to a
   219  // default value.
   220  func (c *Context) ImportCertificateWithAttributes(template AttributeSet, certificate *x509.Certificate) error {
   221  	if c.closed.Get() {
   222  		return errClosed
   223  	}
   224  
   225  	if certificate == nil {
   226  		return errors.New("certificate cannot be nil")
   227  	}
   228  
   229  	serial, err := asn1.Marshal(certificate.SerialNumber)
   230  	if err != nil {
   231  		return err
   232  	}
   233  
   234  	template.AddIfNotPresent([]*pkcs11.Attribute{
   235  		pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_CERTIFICATE),
   236  		pkcs11.NewAttribute(pkcs11.CKA_CERTIFICATE_TYPE, pkcs11.CKC_X_509),
   237  		pkcs11.NewAttribute(pkcs11.CKA_TOKEN, true),
   238  		pkcs11.NewAttribute(pkcs11.CKA_PRIVATE, false),
   239  		pkcs11.NewAttribute(pkcs11.CKA_SUBJECT, certificate.RawSubject),
   240  		pkcs11.NewAttribute(pkcs11.CKA_ISSUER, certificate.RawIssuer),
   241  		pkcs11.NewAttribute(pkcs11.CKA_SERIAL_NUMBER, serial),
   242  		pkcs11.NewAttribute(pkcs11.CKA_VALUE, certificate.Raw),
   243  	})
   244  
   245  	err = c.withSession(func(session *pkcs11Session) error {
   246  		_, err = session.ctx.CreateObject(session.handle, template.ToSlice())
   247  		return err
   248  	})
   249  
   250  	return err
   251  }
   252  
   253  // DeleteCertificate destroys a previously imported certificate. it will return
   254  // nil if succeeds or if the certificate does not exist. Any combination of id,
   255  // label and serial can be provided. An error is return if all are nil.
   256  func (c *Context) DeleteCertificate(id []byte, label []byte, serial *big.Int) error {
   257  	if id == nil && label == nil && serial == nil {
   258  		return errors.New("id, label and serial cannot all be nil")
   259  	}
   260  
   261  	template := []*pkcs11.Attribute{
   262  		pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_CERTIFICATE),
   263  	}
   264  
   265  	if id != nil {
   266  		template = append(template, pkcs11.NewAttribute(pkcs11.CKA_ID, id))
   267  	}
   268  	if label != nil {
   269  		template = append(template, pkcs11.NewAttribute(pkcs11.CKA_LABEL, label))
   270  	}
   271  	if serial != nil {
   272  		asn1Serial, err := asn1.Marshal(serial)
   273  		if err != nil {
   274  			return err
   275  		}
   276  		template = append(template, pkcs11.NewAttribute(pkcs11.CKA_SERIAL_NUMBER, asn1Serial))
   277  	}
   278  
   279  	err := c.withSession(func(session *pkcs11Session) error {
   280  		err := session.ctx.FindObjectsInit(session.handle, template)
   281  		if err != nil {
   282  			return err
   283  		}
   284  		handles, _, err := session.ctx.FindObjects(session.handle, 1)
   285  		finalErr := session.ctx.FindObjectsFinal(session.handle)
   286  		if err != nil {
   287  			return err
   288  		}
   289  		if finalErr != nil {
   290  			return finalErr
   291  		}
   292  		if len(handles) == 0 {
   293  			return nil
   294  		}
   295  		return session.ctx.DestroyObject(session.handle, handles[0])
   296  	})
   297  
   298  	return err
   299  }
   300  

View as plain text