...

Source file src/github.com/miekg/pkcs11/p11/session.go

Documentation: github.com/miekg/pkcs11/p11

     1  package p11
     2  
     3  import (
     4  	"errors"
     5  	"sync"
     6  
     7  	"github.com/miekg/pkcs11"
     8  )
     9  
    10  // ErrNoObjectsFound is returned by FindObject() and FindObjects() if no objects are found.
    11  var ErrNoObjectsFound = errors.New("no objects found")
    12  
    13  // ErrTooManyObjectsFound is returned by FindObject() if multiple objects are found.
    14  var ErrTooManyObjectsFound = errors.New("too many objects matching template")
    15  
    16  // Session represents a PKCS#11 session.
    17  type Session interface {
    18  	// Login logs into the token as a regular user. Note: According to PKCS#11,
    19  	// logged-in state is a property of an application, rather than a session, but
    20  	// you can only log in via a session. Keep this in mind when using multiple
    21  	// sessions on the same token. Logging in to a token in any session will log
    22  	// in all sessions on that token, and logging out will do the same. This is
    23  	// particularly relevant for private keys with CKA_ALWAYS_AUTHENTICATE set
    24  	// (like Yubikeys in PIV mode). See
    25  	// https://github.com/letsencrypt/pkcs11key/blob/master/key.go for an example
    26  	// of managing login state with a mutex.
    27  	Login(pin string) error
    28  	// LoginSecurityOfficer logs into the token as the security officer.
    29  	LoginSecurityOfficer(pin string) error
    30  	// LoginAs logs into the token with the given user type.
    31  	LoginAs(userType uint, pin string) error
    32  	// Logout logs out all sessions from the token (see Login).
    33  	Logout() error
    34  	// Close closes the session.
    35  	Close() error
    36  
    37  	// CreateObject creates an object on the token with the given attributes.
    38  	CreateObject(template []*pkcs11.Attribute) (Object, error)
    39  	// FindObject finds a single object in the token that matches the attributes in
    40  	// the template. It returns error if there is not exactly one result, or if
    41  	// there was an error during the find calls.
    42  	FindObject(template []*pkcs11.Attribute) (Object, error)
    43  	// FindObjects finds any objects in the token matching the template.
    44  	FindObjects(template []*pkcs11.Attribute) ([]Object, error)
    45  	// GenerateKeyPair generates a public/private key pair. It takes
    46  	// GenerateKeyPairRequest instead of individual arguments so that attributes for
    47  	// public and private keys can't be accidentally switched around.
    48  	GenerateKeyPair(request GenerateKeyPairRequest) (*KeyPair, error)
    49  	// GenerateRandom returns random bytes generated by the token.
    50  	GenerateRandom(length int) ([]byte, error)
    51  
    52  	// InitPIN initialize's the normal user's PIN.
    53  	InitPIN(pin string) error
    54  	// SetPIN modifies the PIN of the logged-in user. "old" should contain the
    55  	// current PIN, and "new" should contain the new PIN to be set.
    56  	SetPIN(old, new string) error
    57  }
    58  
    59  type sessionImpl struct {
    60  	sync.Mutex
    61  	ctx    *pkcs11.Ctx
    62  	handle pkcs11.SessionHandle
    63  }
    64  
    65  func (s *sessionImpl) FindPrivateKey(label string) (PrivateKey, error) {
    66  	obj, err := s.findObjectWithClassAndLabel(pkcs11.CKO_PRIVATE_KEY, label)
    67  	if err != nil {
    68  		return PrivateKey(obj), err
    69  	}
    70  	return PrivateKey(obj), nil
    71  }
    72  
    73  func (s *sessionImpl) FindPublicKey(label string) (PublicKey, error) {
    74  	obj, err := s.findObjectWithClassAndLabel(pkcs11.CKO_PUBLIC_KEY, label)
    75  	if err != nil {
    76  		return PublicKey(obj), err
    77  	}
    78  	return PublicKey(obj), nil
    79  }
    80  
    81  func (s *sessionImpl) FindSecretKey(label string) (SecretKey, error) {
    82  	obj, err := s.findObjectWithClassAndLabel(pkcs11.CKO_SECRET_KEY, label)
    83  	if err != nil {
    84  		return SecretKey(obj), err
    85  	}
    86  	return SecretKey(obj), nil
    87  }
    88  
    89  func (s *sessionImpl) findObjectWithClassAndLabel(class uint, label string) (Object, error) {
    90  	return s.FindObject([]*pkcs11.Attribute{
    91  		pkcs11.NewAttribute(pkcs11.CKA_CLASS, class),
    92  		pkcs11.NewAttribute(pkcs11.CKA_LABEL, label),
    93  	})
    94  }
    95  
    96  func (s *sessionImpl) FindObject(template []*pkcs11.Attribute) (Object, error) {
    97  	objects, err := s.FindObjects(template)
    98  	if err != nil {
    99  		return Object{}, err
   100  	}
   101  	if len(objects) > 1 {
   102  		return Object{}, ErrTooManyObjectsFound
   103  	}
   104  	return objects[0], nil
   105  }
   106  
   107  func (s *sessionImpl) FindObjects(template []*pkcs11.Attribute) ([]Object, error) {
   108  	s.Lock()
   109  	defer s.Unlock()
   110  	if err := s.ctx.FindObjectsInit(s.handle, template); err != nil {
   111  		return nil, err
   112  	}
   113  
   114  	var results []Object
   115  	for {
   116  		objectHandles, _, err := s.ctx.FindObjects(s.handle, 100)
   117  		if err != nil {
   118  			_ = s.ctx.FindObjectsFinal(s.handle)
   119  			return nil, err
   120  		} else if len(objectHandles) == 0 {
   121  			break
   122  		}
   123  		i := len(results)
   124  		results = append(results, make([]Object, len(objectHandles))...)
   125  		for j, objectHandle := range objectHandles {
   126  			results[i+j] = Object{
   127  				session:      s,
   128  				objectHandle: objectHandle,
   129  			}
   130  		}
   131  	}
   132  	if err := s.ctx.FindObjectsFinal(s.handle); err != nil {
   133  		return nil, err
   134  	} else if len(results) == 0 {
   135  		return nil, ErrNoObjectsFound
   136  	}
   137  	return results, nil
   138  }
   139  
   140  func (s *sessionImpl) Close() error {
   141  	s.Lock()
   142  	defer s.Unlock()
   143  	return s.ctx.CloseSession(s.handle)
   144  }
   145  
   146  func (s *sessionImpl) Login(pin string) error {
   147  	return s.LoginAs(pkcs11.CKU_USER, pin)
   148  }
   149  
   150  func (s *sessionImpl) LoginSecurityOfficer(pin string) error {
   151  	return s.LoginAs(pkcs11.CKU_SO, pin)
   152  }
   153  
   154  func (s *sessionImpl) LoginAs(userType uint, pin string) error {
   155  	s.Lock()
   156  	defer s.Unlock()
   157  	return s.ctx.Login(s.handle, userType, pin)
   158  }
   159  
   160  func (s *sessionImpl) Logout() error {
   161  	s.Lock()
   162  	defer s.Unlock()
   163  	return s.ctx.Logout(s.handle)
   164  }
   165  
   166  func (s *sessionImpl) GenerateRandom(length int) ([]byte, error) {
   167  	s.Lock()
   168  	defer s.Unlock()
   169  	return s.ctx.GenerateRandom(s.handle, length)
   170  }
   171  
   172  func (s *sessionImpl) CreateObject(template []*pkcs11.Attribute) (Object, error) {
   173  	s.Lock()
   174  	defer s.Unlock()
   175  	oh, err := s.ctx.CreateObject(s.handle, template)
   176  	if err != nil {
   177  		return Object{}, err
   178  	}
   179  	return Object{
   180  		session:      s,
   181  		objectHandle: oh,
   182  	}, nil
   183  }
   184  
   185  func (s *sessionImpl) InitPIN(pin string) error {
   186  	s.Lock()
   187  	defer s.Unlock()
   188  	return s.ctx.InitPIN(s.handle, pin)
   189  }
   190  
   191  func (s *sessionImpl) SetPIN(old, new string) error {
   192  	s.Lock()
   193  	defer s.Unlock()
   194  	return s.ctx.SetPIN(s.handle, old, new)
   195  }
   196  
   197  // KeyPair contains two Objects: one for a public key and one for a private key.
   198  // It represents these as PublicKey and PrivateKey types so they can by used for
   199  // appropriate cryptographic operations.
   200  type KeyPair struct {
   201  	Public  PublicKey
   202  	Private PrivateKey
   203  }
   204  
   205  // GenerateKeyPairRequest contains the fields used to generate a key pair.
   206  type GenerateKeyPairRequest struct {
   207  	Mechanism            pkcs11.Mechanism
   208  	PublicKeyAttributes  []*pkcs11.Attribute
   209  	PrivateKeyAttributes []*pkcs11.Attribute
   210  }
   211  
   212  func (s *sessionImpl) GenerateKeyPair(request GenerateKeyPairRequest) (*KeyPair, error) {
   213  	s.Lock()
   214  	defer s.Unlock()
   215  	pubHandle, privHandle, err := s.ctx.GenerateKeyPair(s.handle,
   216  		[]*pkcs11.Mechanism{&request.Mechanism},
   217  		request.PublicKeyAttributes,
   218  		request.PrivateKeyAttributes)
   219  	if err != nil {
   220  		return nil, err
   221  	}
   222  	return &KeyPair{
   223  		Public: PublicKey(Object{
   224  			session:      s,
   225  			objectHandle: pubHandle,
   226  		}),
   227  		Private: PrivateKey(Object{
   228  			session:      s,
   229  			objectHandle: privHandle,
   230  		}),
   231  	}, nil
   232  }
   233  

View as plain text