pkclient.go 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. package pkclient
  2. import (
  3. "crypto/ecdsa"
  4. "crypto/x509"
  5. "fmt"
  6. "io"
  7. "strconv"
  8. "github.com/stefanberger/go-pkcs11uri"
  9. )
  10. type Client interface {
  11. io.Closer
  12. GetPubKey() ([]byte, error)
  13. DeriveNoise(peerPubKey []byte) ([]byte, error)
  14. Test() error
  15. }
  16. const NoiseKeySize = 32
  17. func FromUrl(pkurl string) (*PKClient, error) {
  18. uri := pkcs11uri.New()
  19. uri.SetAllowAnyModule(true) //todo
  20. err := uri.Parse(pkurl)
  21. if err != nil {
  22. return nil, err
  23. }
  24. module, err := uri.GetModule()
  25. if err != nil {
  26. return nil, err
  27. }
  28. slotid := 0
  29. slot, ok := uri.GetPathAttribute("slot-id", false)
  30. if !ok {
  31. slotid = 0
  32. } else {
  33. slotid, err = strconv.Atoi(slot)
  34. if err != nil {
  35. return nil, err
  36. }
  37. }
  38. pin, _ := uri.GetPIN()
  39. id, _ := uri.GetPathAttribute("id", false)
  40. label, _ := uri.GetPathAttribute("object", false)
  41. return New(module, uint(slotid), pin, id, label)
  42. }
  43. func ecKeyToArray(key *ecdsa.PublicKey) []byte {
  44. x := make([]byte, 32)
  45. y := make([]byte, 32)
  46. key.X.FillBytes(x)
  47. key.Y.FillBytes(y)
  48. return append([]byte{0x04}, append(x, y...)...)
  49. }
  50. func formatPubkeyFromPublicKeyInfoAttr(d []byte) ([]byte, error) {
  51. e, err := x509.ParsePKIXPublicKey(d)
  52. if err != nil {
  53. return nil, err
  54. }
  55. switch t := e.(type) {
  56. case *ecdsa.PublicKey:
  57. return ecKeyToArray(e.(*ecdsa.PublicKey)), nil
  58. default:
  59. return nil, fmt.Errorf("unknown public key type: %T", t)
  60. }
  61. }
  62. func (c *PKClient) Test() error {
  63. pub, err := c.GetPubKey()
  64. if err != nil {
  65. return fmt.Errorf("failed to get public key: %w", err)
  66. }
  67. out, err := c.DeriveNoise(pub) //do an ECDH with ourselves as a quick test
  68. if err != nil {
  69. return err
  70. }
  71. if len(out) != NoiseKeySize {
  72. return fmt.Errorf("got a key of %d bytes, expected %d", len(out), NoiseKeySize)
  73. }
  74. return nil
  75. }