2
0

pkclient_cgo.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. //go:build cgo && pkcs11
  2. package pkclient
  3. import (
  4. "encoding/asn1"
  5. "errors"
  6. "fmt"
  7. "log"
  8. "math/big"
  9. "github.com/miekg/pkcs11"
  10. "github.com/miekg/pkcs11/p11"
  11. )
  12. type PKClient struct {
  13. module p11.Module
  14. session p11.Session
  15. id []byte
  16. label []byte
  17. privKeyObj p11.Object
  18. pubKeyObj p11.Object
  19. }
  20. type ecdsaSignature struct {
  21. R, S *big.Int
  22. }
  23. // New tries to open a session with the HSM, select the slot and login to it
  24. func New(hsmPath string, slotId uint, pin string, id string, label string) (*PKClient, error) {
  25. module, err := p11.OpenModule(hsmPath)
  26. if err != nil {
  27. return nil, fmt.Errorf("failed to load module library: %s", hsmPath)
  28. }
  29. slots, err := module.Slots()
  30. if err != nil {
  31. module.Destroy()
  32. return nil, err
  33. }
  34. // Try to open a session on the slot
  35. slotIdx := 0
  36. for i, slot := range slots {
  37. if slot.ID() == slotId {
  38. slotIdx = i
  39. break
  40. }
  41. }
  42. client := &PKClient{
  43. module: module,
  44. id: []byte(id),
  45. label: []byte(label),
  46. }
  47. client.session, err = slots[slotIdx].OpenWriteSession()
  48. if err != nil {
  49. module.Destroy()
  50. return nil, fmt.Errorf("failed to open session on slot %d", slotId)
  51. }
  52. if len(pin) != 0 {
  53. err = client.session.Login(pin)
  54. if err != nil {
  55. // ignore "already logged in"
  56. if !errors.Is(err, pkcs11.Error(256)) {
  57. _ = client.session.Close()
  58. return nil, fmt.Errorf("unable to login. error: %w", err)
  59. }
  60. }
  61. }
  62. // Make sure the hsm has a private key for deriving
  63. client.privKeyObj, err = client.findDeriveKey(client.id, client.label, true)
  64. if err != nil {
  65. _ = client.Close() //log out, close session, destroy module
  66. return nil, fmt.Errorf("failed to find private key for deriving: %w", err)
  67. }
  68. return client, nil
  69. }
  70. // Close cleans up properly and logs out
  71. func (c *PKClient) Close() error {
  72. var err error = nil
  73. if c.session != nil {
  74. _ = c.session.Logout() //if logout fails, we still want to close
  75. err = c.session.Close()
  76. }
  77. c.module.Destroy()
  78. return err
  79. }
  80. // Try to find a suitable key on the hsm for key derivation
  81. // parameter GET_PUB_KEY sets the search pattern for a public or private key
  82. func (c *PKClient) findDeriveKey(id []byte, label []byte, private bool) (key p11.Object, err error) {
  83. keyClass := pkcs11.CKO_PRIVATE_KEY
  84. if !private {
  85. keyClass = pkcs11.CKO_PUBLIC_KEY
  86. }
  87. keyAttrs := []*pkcs11.Attribute{
  88. //todo, not all HSMs seem to report this, even if its true: pkcs11.NewAttribute(pkcs11.CKA_DERIVE, true),
  89. pkcs11.NewAttribute(pkcs11.CKA_CLASS, keyClass),
  90. }
  91. if id != nil && len(id) != 0 {
  92. keyAttrs = append(keyAttrs, pkcs11.NewAttribute(pkcs11.CKA_ID, id))
  93. }
  94. if label != nil && len(label) != 0 {
  95. keyAttrs = append(keyAttrs, pkcs11.NewAttribute(pkcs11.CKA_LABEL, label))
  96. }
  97. return c.session.FindObject(keyAttrs)
  98. }
  99. func (c *PKClient) listDeriveKeys(id []byte, label []byte, private bool) {
  100. keyClass := pkcs11.CKO_PRIVATE_KEY
  101. if !private {
  102. keyClass = pkcs11.CKO_PUBLIC_KEY
  103. }
  104. keyAttrs := []*pkcs11.Attribute{
  105. pkcs11.NewAttribute(pkcs11.CKA_CLASS, keyClass),
  106. }
  107. if id != nil && len(id) != 0 {
  108. keyAttrs = append(keyAttrs, pkcs11.NewAttribute(pkcs11.CKA_ID, id))
  109. }
  110. if label != nil && len(label) != 0 {
  111. keyAttrs = append(keyAttrs, pkcs11.NewAttribute(pkcs11.CKA_LABEL, label))
  112. }
  113. objects, err := c.session.FindObjects(keyAttrs)
  114. if err != nil {
  115. return
  116. }
  117. for _, obj := range objects {
  118. l, err := obj.Label()
  119. log.Printf("%s, %v", l, err)
  120. a, err := obj.Attribute(pkcs11.CKA_DERIVE)
  121. log.Printf("DERIVE: %s %v, %v", l, a, err)
  122. }
  123. }
  124. // SignASN1 signs some data. Returns the ASN.1 encoded signature.
  125. func (c *PKClient) SignASN1(data []byte) ([]byte, error) {
  126. mech := pkcs11.NewMechanism(pkcs11.CKM_ECDSA_SHA256, nil)
  127. sk := p11.PrivateKey(c.privKeyObj)
  128. rawSig, err := sk.Sign(*mech, data)
  129. if err != nil {
  130. return nil, err
  131. }
  132. // PKCS #11 Mechanisms v2.30:
  133. // "The signature octets correspond to the concatenation of the ECDSA values r and s,
  134. // both represented as an octet string of equal length of at most nLen with the most
  135. // significant byte first. If r and s have different octet length, the shorter of both
  136. // must be padded with leading zero octets such that both have the same octet length.
  137. // Loosely spoken, the first half of the signature is r and the second half is s."
  138. r := new(big.Int).SetBytes(rawSig[:len(rawSig)/2])
  139. s := new(big.Int).SetBytes(rawSig[len(rawSig)/2:])
  140. return asn1.Marshal(ecdsaSignature{r, s})
  141. }
  142. // DeriveNoise derives a shared secret using the input public key against the private key that was found during setup.
  143. // Returns a fixed 32 byte array.
  144. func (c *PKClient) DeriveNoise(peerPubKey []byte) ([]byte, error) {
  145. // Before we call derive, we need to have an array of attributes which specify the type of
  146. // key to be returned, in our case, it's the shared secret key, produced via deriving
  147. // This template pulled from OpenSC pkclient-tool.c line 4038
  148. attrTemplate := []*pkcs11.Attribute{
  149. pkcs11.NewAttribute(pkcs11.CKA_TOKEN, false),
  150. pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_SECRET_KEY),
  151. pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, pkcs11.CKK_GENERIC_SECRET),
  152. pkcs11.NewAttribute(pkcs11.CKA_SENSITIVE, false),
  153. pkcs11.NewAttribute(pkcs11.CKA_EXTRACTABLE, true),
  154. pkcs11.NewAttribute(pkcs11.CKA_ENCRYPT, true),
  155. pkcs11.NewAttribute(pkcs11.CKA_DECRYPT, true),
  156. pkcs11.NewAttribute(pkcs11.CKA_WRAP, true),
  157. pkcs11.NewAttribute(pkcs11.CKA_UNWRAP, true),
  158. }
  159. // Set up the parameters which include the peer's public key
  160. ecdhParams := pkcs11.NewECDH1DeriveParams(pkcs11.CKD_NULL, nil, peerPubKey)
  161. mech := pkcs11.NewMechanism(pkcs11.CKM_ECDH1_DERIVE, ecdhParams)
  162. sk := p11.PrivateKey(c.privKeyObj)
  163. tmpKey, err := sk.Derive(*mech, attrTemplate)
  164. if err != nil {
  165. return nil, err
  166. }
  167. if tmpKey == nil || len(tmpKey) == 0 {
  168. return nil, fmt.Errorf("got an empty secret key")
  169. }
  170. secret := make([]byte, NoiseKeySize)
  171. copy(secret[:], tmpKey[:NoiseKeySize])
  172. return secret, nil
  173. }
  174. func (c *PKClient) GetPubKey() ([]byte, error) {
  175. d, err := c.privKeyObj.Attribute(pkcs11.CKA_PUBLIC_KEY_INFO)
  176. if err != nil {
  177. return nil, err
  178. }
  179. if d != nil && len(d) > 0 {
  180. return formatPubkeyFromPublicKeyInfoAttr(d)
  181. }
  182. c.pubKeyObj, err = c.findDeriveKey(c.id, c.label, false)
  183. if err != nil {
  184. return nil, fmt.Errorf("pkcs11 module gave us a nil CKA_PUBLIC_KEY_INFO, and looking up the public key also failed: %w", err)
  185. }
  186. d, err = c.pubKeyObj.Attribute(pkcs11.CKA_EC_POINT)
  187. if err != nil {
  188. return nil, fmt.Errorf("pkcs11 module gave us a nil CKA_PUBLIC_KEY_INFO, and reading CKA_EC_POINT also failed: %w", err)
  189. }
  190. if d == nil || len(d) < 1 {
  191. return nil, fmt.Errorf("pkcs11 module gave us a nil or empty CKA_EC_POINT")
  192. }
  193. switch len(d) {
  194. case 65: //length of 0x04 + len(X) + len(Y)
  195. return d, nil
  196. case 67: //as above, DER-encoded IIRC?
  197. return d[2:], nil
  198. default:
  199. return nil, fmt.Errorf("unknown public key length: %d", len(d))
  200. }
  201. }