Codebase list golang-github-go-piv-piv-go / 24840b1
New upstream snapshot. Debian Janitor 1 year, 6 months ago
12 changed file(s) with 255 addition(s) and 113 deletion(s). Raw diff Collapse all Expand all
00 name: test
11 on:
2 push:
3 branches:
4 - master
25 pull_request:
36 branches:
47 - master
58
69 jobs:
710 build:
11 strategy:
12 matrix:
13 go-version: [1.18.x, 1.19.x]
814 name: Linux
915 runs-on: ubuntu-latest
1016 steps:
11 - name: Set up Go 1.14
17 - name: Set up Go
1218 uses: actions/setup-go@v2
1319 with:
14 go-version: '^1.14.2'
20 go-version: ${{ matrix.go-version }}
1521 id: go
1622 - name: Check out code into the Go module directory
1723 uses: actions/checkout@v2
18 - name: Install golint
19 run: go get -u golang.org/x/lint/golint
24 - name: Install staticcheck
25 run: go install honnef.co/go/tools/cmd/staticcheck@v0.3.3
2026 - name: Install libpcsc
2127 run: sudo apt-get install -y libpcsclite-dev pcscd pcsc-tools
2228 - name: Test
2329 run: "make test"
2430 build-windows:
31 strategy:
32 matrix:
33 go-version: [1.18.x, 1.19.x]
2534 name: Windows
2635 runs-on: windows-latest
2736 steps:
28 - name: Set up Go 1.14
37 - name: Set up Go
2938 uses: actions/setup-go@v2
3039 with:
31 go-version: '^1.14.2'
40 go-version: ${{ matrix.go-version }}
3241 id: go
3342 - name: Check out code into the Go module directory
3443 uses: actions/checkout@v2
35 - name: Install golint
36 run: go get -u golang.org/x/lint/golint
44 - name: Install staticcheck
45 run: go install honnef.co/go/tools/cmd/staticcheck@v0.3.3
3746 - name: Test
3847 run: "make build"
3948 env:
33
44 .PHONY: lint
55 lint:
6 golint -set_exit_status ./...
6 staticcheck ./...
77
88 .PHONY: build
99 build: lint
120120 fmt.Println("Credentials set. Your PIN is: %s", newPIN)
121121 ```
122122
123 The user can user the PIN later to fetch the management key:
123 The user can use the PIN later to fetch the management key:
124124
125125 ```go
126126 m, err := yk.Metadata(pin)
0 golang-github-go-piv-piv-go (1.10.0+git20220804.1.1902689-1) UNRELEASED; urgency=low
1
2 * New upstream snapshot.
3
4 -- Debian Janitor <janitor@jelmer.uk> Fri, 21 Oct 2022 21:53:34 -0000
5
06 golang-github-go-piv-piv-go (1.8.0-3) unstable; urgency=medium
17
28 [ Debian Janitor ]
00 module github.com/go-piv/piv-go
11
2 go 1.13
2 go 1.16
7575 }
7676
7777 // Formfactor enumerates the physical set of forms a key can take. USB-A vs.
78 // USB-C and Keychain vs. Nano.
78 // USB-C and Keychain vs. Nano (and FIPS variants for these).
7979 type Formfactor int
8080
81 // Formfactors recognized by this package.
81 // The mapping between known Formfactor values and their descriptions.
82 var formFactorStrings = map[Formfactor]string{
83 FormfactorUSBAKeychain: "USB-A Keychain",
84 FormfactorUSBANano: "USB-A Nano",
85 FormfactorUSBCKeychain: "USB-C Keychain",
86 FormfactorUSBCNano: "USB-C Nano",
87 FormfactorUSBCLightningKeychain: "USB-C/Lightning Keychain",
88
89 FormfactorUSBAKeychainFIPS: "USB-A Keychain FIPS",
90 FormfactorUSBANanoFIPS: "USB-A Nano FIPS",
91 FormfactorUSBCKeychainFIPS: "USB-C Keychain FIPS",
92 FormfactorUSBCNanoFIPS: "USB-C Nano FIPS",
93 FormfactorUSBCLightningKeychainFIPS: "USB-C/Lightning Keychain FIPS",
94 }
95
96 // String returns the human-readable description for the given form-factor
97 // value, or a fallback value for any other, unknown form-factor.
98 func (f Formfactor) String() string {
99 if s, ok := formFactorStrings[f]; ok {
100 return s
101 }
102 return fmt.Sprintf("unknown(0x%02x)", int(f))
103 }
104
105 // Formfactors recognized by this package. See the reference for more information:
106 // https://developers.yubico.com/yubikey-manager/Config_Reference.html#_form_factor
82107 const (
83 FormfactorUSBAKeychain = iota + 1
84 FormfactorUSBANano
85 FormfactorUSBCKeychain
86 FormfactorUSBCNano
87 FormfactorUSBCLightningKeychain
108 FormfactorUSBAKeychain = 0x1
109 FormfactorUSBANano = 0x2
110 FormfactorUSBCKeychain = 0x3
111 FormfactorUSBCNano = 0x4
112 FormfactorUSBCLightningKeychain = 0x5
113
114 FormfactorUSBAKeychainFIPS = 0x81
115 FormfactorUSBANanoFIPS = 0x82
116 FormfactorUSBCKeychainFIPS = 0x83
117 FormfactorUSBCNanoFIPS = 0x84
118 FormfactorUSBCLightningKeychainFIPS = 0x85
88119 )
89120
90121 // Prefix in the x509 Subject Common Name for YubiKey attestations
162193 if len(e.Value) != 1 {
163194 return fmt.Errorf("expected 1 byte from formfactor, got: %d", len(e.Value))
164195 }
165 switch e.Value[0] {
166 case 0x01:
167 a.Formfactor = FormfactorUSBAKeychain
168 case 0x02:
169 a.Formfactor = FormfactorUSBANano
170 case 0x03:
171 a.Formfactor = FormfactorUSBCKeychain
172 case 0x04:
173 a.Formfactor = FormfactorUSBCNano
174 case 0x05:
175 a.Formfactor = FormfactorUSBCLightningKeychain
176 default:
177 return fmt.Errorf("unrecognized formfactor: 0x%x", e.Value[0])
178 }
196 a.Formfactor = Formfactor(e.Value[0])
179197 }
180198 return nil
181 }
182
183 func verifySignature(parent, c *x509.Certificate) error {
184 return parent.CheckSignature(c.SignatureAlgorithm, c.RawTBSCertificate, c.Signature)
185199 }
186200
187201 // Verify proves that a key was generated on a YubiKey. It ensures the slot and
193207 }
194208
195209 type verifier struct {
196 Root *x509.Certificate
210 Roots *x509.CertPool
197211 }
198212
199213 func (v *verifier) Verify(attestationCert, slotCert *x509.Certificate) (*Attestation, error) {
200 root := v.Root
201 if root == nil {
202 ca, err := yubicoCA()
214 o := x509.VerifyOptions{KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny}}
215 o.Roots = v.Roots
216 if o.Roots == nil {
217 cas, err := yubicoCAs()
203218 if err != nil {
204 return nil, fmt.Errorf("parsing yubico ca: %v", err)
205 }
206 root = ca
207 }
208 if err := verifySignature(root, attestationCert); err != nil {
209 return nil, fmt.Errorf("attestation certifcate not signed by : %v", err)
210 }
211 if err := verifySignature(attestationCert, slotCert); err != nil {
212 return nil, fmt.Errorf("slot certificate not signed by attestation certifcate: %v", err)
219 return nil, fmt.Errorf("failed to load yubico CAs: %v", err)
220 }
221 o.Roots = cas
222 }
223
224 o.Intermediates = x509.NewCertPool()
225
226 // The attestation cert in some yubikey 4 does not encode X509v3 Basic Constraints.
227 // This isn't valid as per https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.9
228 // (fourth paragraph) and thus makes x509.go validation fail.
229 // Work around this by setting this constraint here.
230 if !attestationCert.BasicConstraintsValid {
231 attestationCert.BasicConstraintsValid = true
232 attestationCert.IsCA = true
233 }
234
235 o.Intermediates.AddCert(attestationCert)
236
237 _, err := slotCert.Verify(o)
238 if err != nil {
239 return nil, fmt.Errorf("error verifying attestation certificate: %v", err)
213240 }
214241 return parseAttestation(slotCert)
215242 }
255282 return RetiredKeyManagementSlot(uint32(key))
256283 }
257284
258 // yubicoPIVCAPEM is the PEM encoded attestation certificate used by Yubico.
285 // yubicoPIVCAPEMAfter2018 is the PEM encoded attestation certificate used by Yubico.
259286 //
260287 // https://developers.yubico.com/PIV/Introduction/PIV_attestation.html
261 const yubicoPIVCAPEM = `-----BEGIN CERTIFICATE-----
288 const yubicoPIVCAPEMAfter2018 = `-----BEGIN CERTIFICATE-----
262289 MIIDFzCCAf+gAwIBAgIDBAZHMA0GCSqGSIb3DQEBCwUAMCsxKTAnBgNVBAMMIFl1
263290 YmljbyBQSVYgUm9vdCBDQSBTZXJpYWwgMjYzNzUxMCAXDTE2MDMxNDAwMDAwMFoY
264291 DzIwNTIwNDE3MDAwMDAwWjArMSkwJwYDVQQDDCBZdWJpY28gUElWIFJvb3QgQ0Eg
278305 SREzU8onbBsjMg9QDiSf5oJLKvd/Ren+zGY7
279306 -----END CERTIFICATE-----`
280307
281 func yubicoCA() (*x509.Certificate, error) {
282 b, _ := pem.Decode([]byte(yubicoPIVCAPEM))
283 if b == nil {
308 // Yubikeys manufactured sometime in 2018 and prior to mid-2017
309 // were certified using the U2F root CA with serial number 457200631
310 // See https://github.com/Yubico/developers.yubico.com/pull/392/commits/a58f1003f003e04fc9baf09cad9f64f0c284fd47
311 // Cert available at https://developers.yubico.com/U2F/yubico-u2f-ca-certs.txt
312 const yubicoPIVCAPEMU2F = `-----BEGIN CERTIFICATE-----
313 MIIDHjCCAgagAwIBAgIEG0BT9zANBgkqhkiG9w0BAQsFADAuMSwwKgYDVQQDEyNZ
314 dWJpY28gVTJGIFJvb3QgQ0EgU2VyaWFsIDQ1NzIwMDYzMTAgFw0xNDA4MDEwMDAw
315 MDBaGA8yMDUwMDkwNDAwMDAwMFowLjEsMCoGA1UEAxMjWXViaWNvIFUyRiBSb290
316 IENBIFNlcmlhbCA0NTcyMDA2MzEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
317 AoIBAQC/jwYuhBVlqaiYWEMsrWFisgJ+PtM91eSrpI4TK7U53mwCIawSDHy8vUmk
318 5N2KAj9abvT9NP5SMS1hQi3usxoYGonXQgfO6ZXyUA9a+KAkqdFnBnlyugSeCOep
319 8EdZFfsaRFtMjkwz5Gcz2Py4vIYvCdMHPtwaz0bVuzneueIEz6TnQjE63Rdt2zbw
320 nebwTG5ZybeWSwbzy+BJ34ZHcUhPAY89yJQXuE0IzMZFcEBbPNRbWECRKgjq//qT
321 9nmDOFVlSRCt2wiqPSzluwn+v+suQEBsUjTGMEd25tKXXTkNW21wIWbxeSyUoTXw
322 LvGS6xlwQSgNpk2qXYwf8iXg7VWZAgMBAAGjQjBAMB0GA1UdDgQWBBQgIvz0bNGJ
323 hjgpToksyKpP9xv9oDAPBgNVHRMECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAN
324 BgkqhkiG9w0BAQsFAAOCAQEAjvjuOMDSa+JXFCLyBKsycXtBVZsJ4Ue3LbaEsPY4
325 MYN/hIQ5ZM5p7EjfcnMG4CtYkNsfNHc0AhBLdq45rnT87q/6O3vUEtNMafbhU6kt
326 hX7Y+9XFN9NpmYxr+ekVY5xOxi8h9JDIgoMP4VB1uS0aunL1IGqrNooL9mmFnL2k
327 LVVee6/VR6C5+KSTCMCWppMuJIZII2v9o4dkoZ8Y7QRjQlLfYzd3qGtKbw7xaF1U
328 sG/5xUb/Btwb2X2g4InpiB/yt/3CpQXpiWX/K4mBvUKiGn05ZsqeY1gx4g0xLBqc
329 U9psmyPzK+Vsgw2jeRQ5JlKDyqE0hebfC1tvFu0CCrJFcw==
330 -----END CERTIFICATE-----`
331
332 func yubicoCAs() (*x509.CertPool, error) {
333 certPool := x509.NewCertPool()
334
335 if !certPool.AppendCertsFromPEM([]byte(yubicoPIVCAPEMAfter2018)) {
336 return nil, fmt.Errorf("failed to parse yubico cert")
337 }
338
339 bU2F, _ := pem.Decode([]byte(yubicoPIVCAPEMU2F))
340 if bU2F == nil {
284341 return nil, fmt.Errorf("failed to decode yubico pem data")
285342 }
286 return x509.ParseCertificate(b.Bytes)
343
344 certU2F, err := x509.ParseCertificate(bU2F.Bytes)
345 if err != nil {
346 return nil, fmt.Errorf("failed to parse yubico cert: %v", err)
347 }
348
349 // The U2F root cert has pathlen x509 basic constraint set to 0.
350 // As per RFC 5280 this means that no intermediate cert is allowed
351 // in the validation path. This isn't really helpful since we do
352 // want to use the device attestation cert as intermediate cert in
353 // the chain. To make this work, set pathlen of the U2F root to 1.
354 //
355 // See https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.9
356 certU2F.MaxPathLen = 1
357 certPool.AddCert(certU2F)
358
359 return certPool, nil
287360 }
288361
289362 // Slot combinations pre-defined by this package.
669742 PINPolicy PINPolicy
670743 }
671744
672 func isAuthErr(err error) bool {
673 var e *apduErr
674 if !errors.As(err, &e) {
675 return false
676 }
677 return e.sw1 == 0x69 && e.sw2 == 0x82 // "security status not satisfied"
678 }
679
680745 func (k KeyAuth) authTx(yk *YubiKey, pp PINPolicy) error {
681746 // PINPolicyNever shouldn't require a PIN.
682747 if pp == PINPolicyNever {
2424 "crypto/x509"
2525 "crypto/x509/pkix"
2626 "encoding/asn1"
27 "encoding/pem"
2728 "errors"
2829 "math/big"
2930 "testing"
765766 t.Fatalf("decrypting data: %v", err)
766767 }
767768
768 if bytes.Compare(data, decrypted) != 0 {
769 if !bytes.Equal(data, decrypted) {
769770 t.Fatalf("decrypted data is different to the source data")
770771 }
771772 })
895896 })
896897 }
897898 }
899
900 func TestVerify(t *testing.T) {
901 tests := []struct {
902 name string
903 deviceCert string
904 keyCert string
905 ok bool
906 }{
907 {
908 // Valid attestation chain from a recent YubiKey.
909 name: "ValidChain",
910 deviceCert: "-----BEGIN CERTIFICATE-----\nMIIC+jCCAeKgAwIBAgIJAKs/UIpBjg1uMA0GCSqGSIb3DQEBCwUAMCsxKTAnBgNV\nBAMMIFl1YmljbyBQSVYgUm9vdCBDQSBTZXJpYWwgMjYzNzUxMCAXDTE2MDMxNDAw\nMDAwMFoYDzIwNTIwNDE3MDAwMDAwWjAhMR8wHQYDVQQDDBZZdWJpY28gUElWIEF0\ndGVzdGF0aW9uMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0zdJWGnk\naLE8Rb+TP7iSffhJV9SJEp2Me4QcfVidgHqyIdo0lruBk69RF1nrmS3i+G1yyUh/\nymAPZkcQCpms0E23Dmhue1VRpBedcsVtO/xSrfu0qAWTslp/k57ry6vkidrQU1cx\nl2KodH3KTmnZmaskQD8eGtxXwcmLOmhKem6GSqhN/3QznaDhZmVUAvUKSOaIzOxn\n2u1mDHhGwaHhR7dklsDwN7oni4WWX1GJXtzpB8j6JhoqyqXwSbq+ck54PfzUoOFd\n/2yKyFRDXnQvzbNL7+afbxBQQMxxo1e24DNE/cp+K09eT7Gh1Urao6meaSssN4aV\nFfmkhC2NapGKMQIDAQABoykwJzARBgorBgEEAYLECgMDBAMFBAMwEgYDVR0TAQH/\nBAgwBgEB/wIBADANBgkqhkiG9w0BAQsFAAOCAQEAJfOLOQYGyIMQ5y+sDkYz+e6G\nH8BqqiYL9VOC3U3KQX9mrtZnaIexqJOCQyCFOSvaTFJvOfNiCCKQuLbmS+Qn4znd\nnSitCsdJSFKskQP7hbXqUK01epb6iTuuko4w3V57YVudnniZBD2s4XoNcJ6BFizZ\n3iXQqRMaLVfFHS9Qx0iLZLcR2s29nIl6NI/qFdIgkyo07J5cPnBiD6wxQft8FdfR\nbgx9yrrjY0mvj/k5LRN6lab8lTolgI5luJtKNueq96LVkTkAzcCaJPQ9YQ4cxeU9\nOapsEeOk6xf5bRPtdf0WhEKthXywt9D0pSHhAI+fpLNe/VtlZpt3hn9aTbqSug==\n-----END CERTIFICATE-----\n",
911 keyCert: "-----BEGIN CERTIFICATE-----\nMIICVTCCAT2gAwIBAgIQAU4Yg7Qnw9FZgMBEaJ7ZMzANBgkqhkiG9w0BAQsFADAh\nMR8wHQYDVQQDDBZZdWJpY28gUElWIEF0dGVzdGF0aW9uMCAXDTE2MDMxNDAwMDAw\nMFoYDzIwNTIwNDE3MDAwMDAwWjAlMSMwIQYDVQQDDBpZdWJpS2V5IFBJViBBdHRl\nc3RhdGlvbiA5YTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABATzM3sJuwemL2Ha\nHkGIzmCVjUMreNIVrRLOvnbZjoVflk1eab/iLUlKzk/2jXTu9TISRg2dhyXcutct\nvnqr66yjTjBMMBEGCisGAQQBgsQKAwMEAwUEAzAUBgorBgEEAYLECgMHBAYCBADw\nDxQwEAYKKwYBBAGCxAoDCAQCAgEwDwYKKwYBBAGCxAoDCQQBBDANBgkqhkiG9w0B\nAQsFAAOCAQEAFX0hL5gi/g4ZM7vCH5kDAtma7eBp0LpbCzR313GGyBR7pJFtuj2l\nbWU+V3SFRihXBTDb8q+uvyCBqgz1szdZzrpfjqNkhEPfPNabxjxJxVoe6Gdcn115\naduxfqqT2u+YIsERzaIIIisehLQkc/5zLkpocA6jbKBZnZWUBJIxuz4QmYTIf0O4\nHPE2o4JbAyGx/hRaqVvDgNeAz94ZFjb4Mp3RNbbdRUZB0ehrT/IGRJoHRu2HKFGM\nylRJL2kjKPoEc4XHbCu+MfmAIrQ4Xseg85zyI7ThhYvAzktdLHhQyfYr4wrrLCN3\noeTzmiqIHe9AataJXQ+mEQEEc9TNY23RFg==\n-----END CERTIFICATE-----\n",
912 ok: true,
913 },
914 {
915 // Valid attestation chain from a yubikey manufactured in 2018 showing a manufacture bug (device certified using U2F root, and device cert does not encode X509 basic constraints).
916 name: "ValidChain2018",
917 deviceCert: "-----BEGIN CERTIFICATE-----\nMIIC6TCCAdGgAwIBAgIJALvwZFDESwMlMA0GCSqGSIb3DQEBCwUAMC4xLDAqBgNV\nBAMTI1l1YmljbyBVMkYgUm9vdCBDQSBTZXJpYWwgNDU3MjAwNjMxMCAXDTE0MDgw\nMTAwMDAwMFoYDzIwNTAwOTA0MDAwMDAwWjAhMR8wHQYDVQQDDBZZdWJpY28gUElW\nIEF0dGVzdGF0aW9uMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqXnZ\n+lxX0nNzy3jn+lrZ+1cHTVUNYVKPqGTjvRw/7XOEnInWC1VCPJqwHYtnnoH4EIXN\n7kDGXwInfs9pwyjpgQw/V23yywFtUhaR8Xgw8zqC/YfJpeK4PetJ9/k+xFbICuX7\nWDv/k5Wth3VZSaVjm/tunWajtt3OLOQQaMSoLqP41XAHHuCyzfCwJ2Vsa2FyCINF\nyG6XobokeICDRnH44POqudcLVIDvZLQqu2LF+mZd+OO5nqmTa68kkwRf/m93eOJP\no7GvYtQSp7CPJC7ks2gl8U7wuT9DQT5/0wqkoEyLZg/KLUlzgXjMa+7GtCLTC1Ku\nOh9vw02f4K44RW4nWwIDAQABoxUwEzARBgorBgEEAYLECgMDBAMEAwcwDQYJKoZI\nhvcNAQELBQADggEBAHD/uXqNgCYywj2ee7s7kix2TT4XN9OIn0fTNh5LEiUN+q7U\nzJc9q7b5WD7PfaG6UNyuaSnLaq+dLOCJ4bX4h+/MwQSndQg0epMra1ThVQZkMkGa\nktAJ5JT6j9qxNxD1RWMl91e4JwtGzFyDwFyyUGnSwhMsqMdwfBsmTpvgxmAD/NMs\nkWB/m91FV9D+UBqsZRoLoc44kEFYBZ09ypTsR699oJRsBfG0AqVYyK7rnG6663fF\nGUSWk7noVdUPXedlwXCqCymCsVheoss9qF1cffaFIl9RxGvVvCFybx0LGiYDxfgv\n80yGZIY/mAqZVDWyHZSs4f6kWK9GeLKU2Y9yby4=\n-----END CERTIFICATE-----\n",
918 keyCert: "-----BEGIN CERTIFICATE-----\nMIICLzCCARegAwIBAgIRAIxiihk4fSKK6keqJYujvnkwDQYJKoZIhvcNAQELBQAw\nITEfMB0GA1UEAwwWWXViaWNvIFBJViBBdHRlc3RhdGlvbjAgFw0xNDA4MDEwMDAw\nMDBaGA8yMDUwMDkwNDAwMDAwMFowJTEjMCEGA1UEAwwaWXViaUtleSBQSVYgQXR0\nZXN0YXRpb24gOWEwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATHEzJsrhTHuvsx\n685AiWsAuT8Poe/zQfDRZNfpUSzJ31v6MZ9nz70pNrdd/sbG7O1UA6ceWhq1jHTU\n96Dnp99voycwJTARBgorBgEEAYLECgMDBAMEAwcwEAYKKwYBBAGCxAoDCAQCAgEw\nDQYJKoZIhvcNAQELBQADggEBADoswZ1LJ5GYVNgtRE0+zMQkAzam8YqeKmIDHtir\nvolIpGtJHzgCG2SdJlR/KnjRWF/1i8TRMhQ0O/KgkIEh+IyhJtD7DojgWvIBsCnX\nJXF7EPQMy17l7/9940QSOnQRIDb+z0eq9ACAjC3FWzqeR5VgN4C1QpCw7gKgqLTs\npmmDHHg4HsKl0PsPwim0bYIqEHttrLjPQiPnoa3qixzNKbwJjXb4/f/dvCTx9dRP\n0FVABj5Yh8f728xzrzw2nLZ9X/c0GoXfKu9s7lGNLcZ5OO+zys1ATei2h/PFJLDH\nAdrenw31WOYRtdjcNBKyAk80ajryjTAX3GXfbKpkdVB9hEo=\n-----END CERTIFICATE-----\n",
919 ok: true,
920 },
921 {
922 // Invalid attestation chain. Device cert from yubikey A, key cert from yubikey B.
923 name: "InvalidChain",
924 deviceCert: "-----BEGIN CERTIFICATE-----\nMIIC+jCCAeKgAwIBAgIJAKs/UIpBjg1uMA0GCSqGSIb3DQEBCwUAMCsxKTAnBgNV\nBAMMIFl1YmljbyBQSVYgUm9vdCBDQSBTZXJpYWwgMjYzNzUxMCAXDTE2MDMxNDAw\nMDAwMFoYDzIwNTIwNDE3MDAwMDAwWjAhMR8wHQYDVQQDDBZZdWJpY28gUElWIEF0\ndGVzdGF0aW9uMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0zdJWGnk\naLE8Rb+TP7iSffhJV9SJEp2Me4QcfVidgHqyIdo0lruBk69RF1nrmS3i+G1yyUh/\nymAPZkcQCpms0E23Dmhue1VRpBedcsVtO/xSrfu0qAWTslp/k57ry6vkidrQU1cx\nl2KodH3KTmnZmaskQD8eGtxXwcmLOmhKem6GSqhN/3QznaDhZmVUAvUKSOaIzOxn\n2u1mDHhGwaHhR7dklsDwN7oni4WWX1GJXtzpB8j6JhoqyqXwSbq+ck54PfzUoOFd\n/2yKyFRDXnQvzbNL7+afbxBQQMxxo1e24DNE/cp+K09eT7Gh1Urao6meaSssN4aV\nFfmkhC2NapGKMQIDAQABoykwJzARBgorBgEEAYLECgMDBAMFBAMwEgYDVR0TAQH/\nBAgwBgEB/wIBADANBgkqhkiG9w0BAQsFAAOCAQEAJfOLOQYGyIMQ5y+sDkYz+e6G\nH8BqqiYL9VOC3U3KQX9mrtZnaIexqJOCQyCFOSvaTFJvOfNiCCKQuLbmS+Qn4znd\nnSitCsdJSFKskQP7hbXqUK01epb6iTuuko4w3V57YVudnniZBD2s4XoNcJ6BFizZ\n3iXQqRMaLVfFHS9Qx0iLZLcR2s29nIl6NI/qFdIgkyo07J5cPnBiD6wxQft8FdfR\nbgx9yrrjY0mvj/k5LRN6lab8lTolgI5luJtKNueq96LVkTkAzcCaJPQ9YQ4cxeU9\nOapsEeOk6xf5bRPtdf0WhEKthXywt9D0pSHhAI+fpLNe/VtlZpt3hn9aTbqSug==\n-----END CERTIFICATE-----\n",
925 keyCert: "-----BEGIN CERTIFICATE-----\nMIICLzCCARegAwIBAgIRAIxiihk4fSKK6keqJYujvnkwDQYJKoZIhvcNAQELBQAw\nITEfMB0GA1UEAwwWWXViaWNvIFBJViBBdHRlc3RhdGlvbjAgFw0xNDA4MDEwMDAw\nMDBaGA8yMDUwMDkwNDAwMDAwMFowJTEjMCEGA1UEAwwaWXViaUtleSBQSVYgQXR0\nZXN0YXRpb24gOWEwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATHEzJsrhTHuvsx\n685AiWsAuT8Poe/zQfDRZNfpUSzJ31v6MZ9nz70pNrdd/sbG7O1UA6ceWhq1jHTU\n96Dnp99voycwJTARBgorBgEEAYLECgMDBAMEAwcwEAYKKwYBBAGCxAoDCAQCAgEw\nDQYJKoZIhvcNAQELBQADggEBADoswZ1LJ5GYVNgtRE0+zMQkAzam8YqeKmIDHtir\nvolIpGtJHzgCG2SdJlR/KnjRWF/1i8TRMhQ0O/KgkIEh+IyhJtD7DojgWvIBsCnX\nJXF7EPQMy17l7/9940QSOnQRIDb+z0eq9ACAjC3FWzqeR5VgN4C1QpCw7gKgqLTs\npmmDHHg4HsKl0PsPwim0bYIqEHttrLjPQiPnoa3qixzNKbwJjXb4/f/dvCTx9dRP\n0FVABj5Yh8f728xzrzw2nLZ9X/c0GoXfKu9s7lGNLcZ5OO+zys1ATei2h/PFJLDH\nAdrenw31WOYRtdjcNBKyAk80ajryjTAX3GXfbKpkdVB9hEo=\n-----END CERTIFICATE-----\n",
926 ok: false,
927 },
928 {
929 // Invalid attestation chain. Device cert from yubikey B, key cert from yubikey A.
930 name: "InvalidChain2",
931 deviceCert: "-----BEGIN CERTIFICATE-----\nMIIC6TCCAdGgAwIBAgIJALvwZFDESwMlMA0GCSqGSIb3DQEBCwUAMC4xLDAqBgNV\nBAMTI1l1YmljbyBVMkYgUm9vdCBDQSBTZXJpYWwgNDU3MjAwNjMxMCAXDTE0MDgw\nMTAwMDAwMFoYDzIwNTAwOTA0MDAwMDAwWjAhMR8wHQYDVQQDDBZZdWJpY28gUElW\nIEF0dGVzdGF0aW9uMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqXnZ\n+lxX0nNzy3jn+lrZ+1cHTVUNYVKPqGTjvRw/7XOEnInWC1VCPJqwHYtnnoH4EIXN\n7kDGXwInfs9pwyjpgQw/V23yywFtUhaR8Xgw8zqC/YfJpeK4PetJ9/k+xFbICuX7\nWDv/k5Wth3VZSaVjm/tunWajtt3OLOQQaMSoLqP41XAHHuCyzfCwJ2Vsa2FyCINF\nyG6XobokeICDRnH44POqudcLVIDvZLQqu2LF+mZd+OO5nqmTa68kkwRf/m93eOJP\no7GvYtQSp7CPJC7ks2gl8U7wuT9DQT5/0wqkoEyLZg/KLUlzgXjMa+7GtCLTC1Ku\nOh9vw02f4K44RW4nWwIDAQABoxUwEzARBgorBgEEAYLECgMDBAMEAwcwDQYJKoZI\nhvcNAQELBQADggEBAHD/uXqNgCYywj2ee7s7kix2TT4XN9OIn0fTNh5LEiUN+q7U\nzJc9q7b5WD7PfaG6UNyuaSnLaq+dLOCJ4bX4h+/MwQSndQg0epMra1ThVQZkMkGa\nktAJ5JT6j9qxNxD1RWMl91e4JwtGzFyDwFyyUGnSwhMsqMdwfBsmTpvgxmAD/NMs\nkWB/m91FV9D+UBqsZRoLoc44kEFYBZ09ypTsR699oJRsBfG0AqVYyK7rnG6663fF\nGUSWk7noVdUPXedlwXCqCymCsVheoss9qF1cffaFIl9RxGvVvCFybx0LGiYDxfgv\n80yGZIY/mAqZVDWyHZSs4f6kWK9GeLKU2Y9yby4=\n-----END CERTIFICATE-----\n",
932 keyCert: "-----BEGIN CERTIFICATE-----\nMIICVTCCAT2gAwIBAgIQAU4Yg7Qnw9FZgMBEaJ7ZMzANBgkqhkiG9w0BAQsFADAh\nMR8wHQYDVQQDDBZZdWJpY28gUElWIEF0dGVzdGF0aW9uMCAXDTE2MDMxNDAwMDAw\nMFoYDzIwNTIwNDE3MDAwMDAwWjAlMSMwIQYDVQQDDBpZdWJpS2V5IFBJViBBdHRl\nc3RhdGlvbiA5YTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABATzM3sJuwemL2Ha\nHkGIzmCVjUMreNIVrRLOvnbZjoVflk1eab/iLUlKzk/2jXTu9TISRg2dhyXcutct\nvnqr66yjTjBMMBEGCisGAQQBgsQKAwMEAwUEAzAUBgorBgEEAYLECgMHBAYCBADw\nDxQwEAYKKwYBBAGCxAoDCAQCAgEwDwYKKwYBBAGCxAoDCQQBBDANBgkqhkiG9w0B\nAQsFAAOCAQEAFX0hL5gi/g4ZM7vCH5kDAtma7eBp0LpbCzR313GGyBR7pJFtuj2l\nbWU+V3SFRihXBTDb8q+uvyCBqgz1szdZzrpfjqNkhEPfPNabxjxJxVoe6Gdcn115\naduxfqqT2u+YIsERzaIIIisehLQkc/5zLkpocA6jbKBZnZWUBJIxuz4QmYTIf0O4\nHPE2o4JbAyGx/hRaqVvDgNeAz94ZFjb4Mp3RNbbdRUZB0ehrT/IGRJoHRu2HKFGM\nylRJL2kjKPoEc4XHbCu+MfmAIrQ4Xseg85zyI7ThhYvAzktdLHhQyfYr4wrrLCN3\noeTzmiqIHe9AataJXQ+mEQEEc9TNY23RFg==\n-----END CERTIFICATE-----\n",
933 ok: false,
934 },
935 }
936
937 parseCert := func(cert string) (*x509.Certificate, error) {
938 block, _ := pem.Decode([]byte(cert))
939 if block == nil {
940 t.Fatalf("decoding PEM cert, empty block")
941 }
942 return x509.ParseCertificate(block.Bytes)
943 }
944
945 for _, test := range tests {
946 t.Run(test.name, func(t *testing.T) {
947 deviceCert, err := parseCert(test.deviceCert)
948 if err != nil {
949 t.Fatalf("parsing device cert: %v", err)
950 }
951
952 keyCert, err := parseCert(test.keyCert)
953 if err != nil {
954 t.Fatalf("parsing key cert: %v", err)
955 }
956
957 _, err = Verify(deviceCert, keyCert)
958 if (err == nil) != test.ok {
959 t.Errorf("Verify returned %v, expected test outcome %v", err, test.ok)
960 }
961 })
962 }
963 }
2525 }
2626
2727 func isRCNoReaders(rc C.long) bool {
28 return rc == 0x8010002E
28 return uint32(rc) == 0x8010002E
2929 }
0 // Copyright 2020 Google LLC
1 //
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // https://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13
14 package piv
15
16 import "C"
17
18 // Return codes for PCSC are different on different platforms (int vs. long).
19
20 func scCheck(rc C.long) error {
21 if rc == rcSuccess {
22 return nil
23 }
24 return &scErr{int64(rc)}
25 }
26
27 func isRCNoReaders(rc C.long) bool {
28 return rc == 0x8010002E
29 }
1111 // See the License for the specific language governing permissions and
1212 // limitations under the License.
1313
14 // +build darwin linux freebsd
14 //go:build darwin || linux || freebsd || openbsd
15 // +build darwin linux freebsd openbsd
1516
1617 package piv
1718
2324 // #cgo freebsd CFLAGS: -I/usr/local/include/PCSC
2425 // #cgo freebsd LDFLAGS: -L/usr/local/lib/
2526 // #cgo freebsd LDFLAGS: -lpcsclite
27 // #cgo openbsd CFLAGS: -I/usr/local/include/
28 // #cgo openbsd CFLAGS: -I/usr/local/include/PCSC
29 // #cgo openbsd LDFLAGS: -L/usr/local/lib/
30 // #cgo openbsd LDFLAGS: -lpcsclite
2631 // #include <PCSC/winscard.h>
2732 // #include <PCSC/wintypes.h>
2833 import "C"
126126 handle syscall.Handle
127127 activeProtocol uint16
128128 )
129 readerPtr, err := syscall.UTF16PtrFromString(reader)
130 if err != nil {
131 return nil, fmt.Errorf("invalid reader string: %v", err)
132 }
129133 r0, _, _ := procSCardConnectW.Call(
130134 uintptr(c.ctx),
131 uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(reader))),
135 uintptr(unsafe.Pointer(readerPtr)),
132136 scardShareExclusive,
133137 scardProtocolT1,
134138 uintptr(unsafe.Pointer(&handle)),
401401 response := make([]byte, 8)
402402 block.Encrypt(response, challenge)
403403
404 data := append([]byte{
404 data := []byte{
405405 0x7c, // Dynamic Authentication Template tag
406406 20, // 2+8+2+8
407407 0x80, // 'Witness'
408408 0x08, // Tag length
409 })
409 }
410410 data = append(data, cardResponse...)
411411 data = append(data,
412412 0x81, // 'Challenge'
631631 return binary.BigEndian.Uint32(resp), nil
632632 }
633633
634 // ykChangeManagementKey sets the Management Key to the new key provided. The
635 // user must have authenticated with the existing key first.
636 func ykChangeManagementKey(tx *scTx, key [24]byte) error {
637 cmd := apdu{
638 instruction: insSetMGMKey,
639 param1: 0xff,
640 param2: 0xff, // TODO: support touch policy
641 data: append([]byte{
642 alg3DES, keyCardManagement, 24,
643 }, key[:]...),
644 }
645 if _, err := tx.Transmit(cmd); err != nil {
646 return fmt.Errorf("command failed: %w", err)
647 }
648 return nil
649 }
650
651 func unmarshalDERField(b []byte, tag uint64) (obj []byte, err error) {
652 var prefix []byte
653 for tag > 0 {
654 prefix = append(prefix, byte(tag))
655 tag = tag >> 8
656 }
657 for i, j := 0, len(prefix)-1; i < j; i, j = i+1, j-1 {
658 prefix[i], prefix[j] = prefix[j], prefix[i]
659 }
660
661 hasPrefix := bytes.HasPrefix(b, prefix)
662 for len(b) > 0 {
663 var v asn1.RawValue
664 b, err = asn1.Unmarshal(b, &v)
665 if err != nil {
666 return nil, err
667 }
668 if hasPrefix {
669 return v.Bytes, nil
670 }
671 }
672 return nil, fmt.Errorf("no der value with tag 0x%x", prefix)
673 }
674
675634 // Metadata returns protected data stored on the card. This can be used to
676635 // retrieve PIN protected management keys.
677636 func (yk *YubiKey) Metadata(pin string) (*Metadata, error) {
779738 return fmt.Errorf("invalid management key length: %d", len(v.Bytes))
780739 }
781740 var key [24]byte
782 for i := 0; i < len(v.Bytes); i++ {
783 key[i] = v.Bytes[i]
784 }
741 copy(key[:], v.Bytes)
785742 m.ManagementKey = &key
786743 }
787744 return nil