-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,10 @@ | ||
// SPDX-FileCopyrightText: 2020 Google LLC | ||
// SPDX-FileCopyrightText: 2023-2024 Steffen Vogel <[email protected]> | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package piv | ||
|
||
type algorithmType byte | ||
|
||
const ( | ||
AlgTypeRSA algorithmType = iota + 1 | ||
AlgTypeECCP | ||
AlgTypeEd25519 | ||
) | ||
import "fmt" | ||
|
||
// Algorithm represents a specific algorithm and bit size supported by the PIV | ||
// specification. | ||
|
@@ -18,41 +13,93 @@ type Algorithm byte | |
// Algorithms supported by this package. Note that not all cards will support | ||
// every algorithm. | ||
// | ||
// AlgorithmEd25519 is currently only implemented by SoloKeys. | ||
// | ||
// For algorithm discovery, see: https://github.com/ericchiang/piv-go/issues/1 | ||
// For algorithm discovery, see: https://github.com/go-piv/piv-go/issues/1 | ||
const ( | ||
Alg3DES Algorithm = 0x03 | ||
AlgRSA1024 Algorithm = 0x06 | ||
AlgRSA2048 Algorithm = 0x07 | ||
AlgRSA3072 Algorithm = 0x05 | ||
// NIST SP 800-78-4 | ||
// https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-73-4.pdf#page=21 | ||
AlgRSA2048 Algorithm = 0x07 // RSA 2048 bit modulus, 65537 ≤ exponent ≤ 2256 - 1 | ||
AlgECCP256 Algorithm = 0x11 // ECC: Curve P-256 | ||
AlgECCP384 Algorithm = 0x14 // ECC: Curve P-384 | ||
|
||
// NIST SP 800-78-5 ipd (Initial Public Draft) | ||
// https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-78-5.ipd.pdf#page=12 | ||
Alg3DESSalt Algorithm = 0x00 // 3 Key Triple DES – ECB (deprecated) | ||
Alg3DES Algorithm = 0x03 // 3 Key Triple DES – ECB (deprecated) | ||
AlgRSA3072 Algorithm = 0x05 // RSA 3072 bit modulus, 65537 ≤ exponent ≤ 2256 - 1 | ||
AlgRSA1024 Algorithm = 0x06 // RSA 1024 bit modulus, 65537 ≤ exponent ≤ 2256 - 1 | ||
AlgAES128 Algorithm = 0x08 // AES-128 – ECB | ||
AlgAES192 Algorithm = 0x0A // AES-192 – ECB | ||
AlgAES256 Algorithm = 0x0C // AES-256 – ECB | ||
AlgCS2 Algorithm = 0x27 // Cipher Suite 2 | ||
AlgCS7 Algorithm = 0x2E // Cipher Suite 7 | ||
|
||
// Non-standard extensions | ||
AlgPIN Algorithm = 0xFF | ||
|
||
// YubiKey 5.7 Firmware Specifics - PIV Enhancements - Additional Key Types Supported | ||
// | ||
// https://docs.yubico.com/hardware/yubikey/yk-tech-manual/5.7-firmware-specifics.html#additional-key-types-supported | ||
AlgRSA4096 Algorithm = 0x16 | ||
AlgECCP256 Algorithm = 0x11 | ||
AlgECCP384 Algorithm = 0x14 | ||
|
||
// Non-standard; as implemented by SoloKeys. Chosen for low probability of eventual | ||
// clashes, if and when PIV standard adds Ed25519 support | ||
AlgEd25519 Algorithm = 0x22 | ||
AlgEd25519 Algorithm = 0xE0 // YubiKey | ||
AlgX25519 Algorithm = 0xE1 // YubiKey | ||
|
||
// Trussed PIV authenticator (NitroKey / SoloKeys) | ||
// | ||
// https://github.com/Nitrokey/piv-authenticator/blob/efb4632b3f498af6732fc716354af746f3960038/tests/command_response.rs#L58-L72 | ||
|
||
// AlgECCP521 Algorithm = 0x15 | ||
// AlgRSA3072 Algorithm = 0xE0 | ||
// AlgRSA4096 Algorithm = 0xE1 | ||
// AlgEd25519 Algorithm = 0xE2 | ||
// AlgX25519 Algorithm = 0xE3 | ||
// AlgEd448 Algorithm = 0xE4 | ||
// AlgX448 Algorithm = 0xE5 | ||
|
||
// Internal algorithms for testing | ||
algRSA512 Algorithm = 0xF0 | ||
algECCP224 Algorithm = 0xF1 | ||
algECCP521 Algorithm = 0xF2 | ||
) | ||
|
||
func (a Algorithm) algType() algorithmType { | ||
func (a Algorithm) String() string { | ||
switch a { | ||
case AlgRSA1024, AlgRSA2048, AlgRSA3072, AlgRSA4096: | ||
return AlgTypeRSA | ||
case AlgRSA1024, AlgRSA2048, AlgRSA3072, AlgRSA4096, algRSA512: | ||
return fmt.Sprintf("RSA-%d", a.bits()) | ||
|
||
case AlgECCP256, AlgECCP384, algECCP224, algECCP521: | ||
return fmt.Sprintf("P-%d", a.bits()) | ||
|
||
case Alg3DESSalt: | ||
return "3DESSalt" | ||
case Alg3DES: | ||
return "3DES" | ||
|
||
case AlgAES128, AlgAES192, AlgAES256: | ||
return fmt.Sprintf("AES-%d", a.bits()) | ||
|
||
case AlgECCP256, AlgECCP384: | ||
return AlgTypeECCP | ||
case AlgCS2: | ||
return "CS2" | ||
case AlgCS7: | ||
return "CS7" | ||
|
||
case AlgPIN: | ||
return "PIN" | ||
|
||
case AlgEd25519: | ||
return AlgTypeEd25519 | ||
return "Ed25519" | ||
case AlgX25519: | ||
return "X25519" | ||
|
||
default: | ||
return 0 | ||
return "" | ||
} | ||
} | ||
|
||
func (a Algorithm) bits() int { | ||
switch a { | ||
case algRSA512: | ||
return 512 | ||
case AlgRSA1024: | ||
return 1024 | ||
case AlgRSA2048: | ||
|
@@ -62,10 +109,21 @@ func (a Algorithm) bits() int { | |
case AlgRSA4096: | ||
return 4096 | ||
|
||
case algECCP224: | ||
return 224 | ||
case AlgECCP256: | ||
return 256 | ||
case AlgECCP384: | ||
return 384 | ||
case algECCP521: | ||
return 521 | ||
|
||
case AlgAES128: | ||
return 128 | ||
case AlgAES192: | ||
return 192 | ||
case AlgAES256: | ||
return 256 | ||
|
||
default: | ||
return 0 | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,42 +1,18 @@ | ||
cunicu.li/go-iso7816 v0.3.0 h1:KSt0D7TBh0ghWnpDSjNJDehFmXwM67Q8I3Qg0fvZlgw= | ||
cunicu.li/go-iso7816 v0.3.0/go.mod h1:jL3bciDEU4prkEtONmCzVAz542Vb7SLJBnLV3o4o8qo= | ||
cunicu.li/go-iso7816 v0.4.0 h1:GwYTCcaGlaNC+Tb+TVVqGTKX83Z/UALM1U388Ymgfec= | ||
cunicu.li/go-iso7816 v0.4.0/go.mod h1:jL3bciDEU4prkEtONmCzVAz542Vb7SLJBnLV3o4o8qo= | ||
cunicu.li/go-iso7816 v0.5.0 h1:HjjEZFw5DqNukwswPBtHrt/iqfuZ2zZsHEhmasT7eXI= | ||
cunicu.li/go-iso7816 v0.5.0/go.mod h1:jL3bciDEU4prkEtONmCzVAz542Vb7SLJBnLV3o4o8qo= | ||
cunicu.li/go-iso7816 v0.5.1 h1:0fsdN5j+AoU9Y32RfF2IR126xpYAU1CC9WNBV6zmZAs= | ||
cunicu.li/go-iso7816 v0.5.1/go.mod h1:OwF8/IxfJAi/GEuMv3cv7jXFmbto+7lDwl2eknMucoA= | ||
cunicu.li/go-iso7816 v0.5.2 h1:hdGm6xLZ5//FjRSFxMRfuqfEFDIu6bIlKreKrXH6Fx8= | ||
cunicu.li/go-iso7816 v0.5.2/go.mod h1:OwF8/IxfJAi/GEuMv3cv7jXFmbto+7lDwl2eknMucoA= | ||
cunicu.li/go-iso7816 v0.6.0 h1:l0CzHZWN7FFLJOGY1NUQGyRxv0IuZODpMvEHWFIvOz4= | ||
cunicu.li/go-iso7816 v0.6.0/go.mod h1:DBXPMv/k9XQplA9qQT2k/Xo2gPCWQ9/rIh+h4hzJ850= | ||
cunicu.li/go-iso7816 v0.8.0 h1:EEQ9hAbdIbTUM0uVrWbfGnQnFjA3P/VoNj1GM71Tf5w= | ||
cunicu.li/go-iso7816 v0.8.0/go.mod h1:gSG/jc0iH2bykUasCbyIfnI1PFotnm76Gmk1bc7UFEg= | ||
cunicu.li/go-iso7816 v0.8.1 h1:3kgjW+iCwkw6DtLDh5aKUQfwpwd0zoHHyPxyDS9t7HU= | ||
cunicu.li/go-iso7816 v0.8.1/go.mod h1:bt5Uo0kVcv8+wbIaMdWw3YrcwdhGEDCu/arp7dsHuTY= | ||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/ebfe/scard v0.0.0-20230420082256-7db3f9b7c8a7 h1:HYAhfGa9dEemCZgGZWL5AvVsctBCsHxl2CI0HUXzHQE= | ||
github.com/ebfe/scard v0.0.0-20230420082256-7db3f9b7c8a7/go.mod h1:BkYEeWL6FbT4Ek+TcOBnPzEKnL7kOq2g19tTQXkorHY= | ||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= | ||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= | ||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= | ||
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= | ||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= | ||
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= | ||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= | ||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | ||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= | ||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= | ||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= | ||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= | ||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= | ||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= | ||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | ||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
// SPDX-FileCopyrightText: 2020 Google LLC | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package piv | ||
|
||
import ( | ||
"crypto/ecdh" | ||
"fmt" | ||
|
||
iso "cunicu.li/go-iso7816" | ||
"cunicu.li/go-iso7816/encoding/tlv" | ||
) | ||
|
||
type keyX25519 struct { | ||
c *Card | ||
slot Slot | ||
pub *ecdh.PublicKey | ||
auth KeyAuth | ||
pp PINPolicy | ||
} | ||
|
||
func (k *keyX25519) Public() *ecdh.PublicKey { | ||
return k.pub | ||
} | ||
|
||
// SharedKey performs a Diffie-Hellman key agreement with the peer | ||
// to produce a shared secret key. | ||
// | ||
// Peer's public key must use the same algorithm as the key in | ||
// this slot, or an error will be returned. | ||
// | ||
// Length of the result depends on the types and sizes of the keys | ||
// used for the operation. Callers should use a cryptographic key | ||
// derivation function to extract the amount of bytes they need. | ||
func (k *keyX25519) SharedKey(peer *ecdh.PublicKey) ([]byte, error) { | ||
if peer.Curve() != k.pub.Curve() { | ||
return nil, errMismatchingAlgorithms | ||
} | ||
|
||
return k.auth.do(k.c, k.pp, func(tx *iso.Transaction) ([]byte, error) { | ||
Check failure on line 40 in key_ecdh.go
|
||
// https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-73-4.pdf#page=118 | ||
// https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-73-4.pdf#page=93 | ||
resp, err := sendTLV(k.c.tx, iso.InsGeneralAuthenticate, byte(AlgX25519), k.slot.Key, | ||
tlv.New(0x7c, | ||
tlv.New(0x82), | ||
tlv.New(0x85, peer.Bytes()), | ||
), | ||
) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to execute command: %w", err) | ||
} | ||
|
||
rs, _, ok := resp.GetChild(0x7c, 0x82) | ||
if !ok { | ||
return nil, fmt.Errorf("%w: missing tag", errUnmarshal) | ||
} | ||
return rs, nil | ||
}) | ||
} | ||
|
||
// https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-73-4.pdf#page=95 | ||
func decodeX25519Public(tvs tlv.TagValues) (*ecdh.PublicKey, error) { | ||
p, _, ok := tvs.Get(0x86) | ||
if !ok { | ||
return nil, fmt.Errorf("%w points", errUnmarshal) | ||
} | ||
|
||
if len(p) != 32 { | ||
return nil, fmt.Errorf("%w of points: %d", errUnexpectedLength, len(p)) | ||
} | ||
|
||
return ecdh.X25519().NewPublicKey(p) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
// SPDX-FileCopyrightText: 2023-2024 Steffen Vogel <post@steffenvogel.de> | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package piv |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.