-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
smartcard handler for request authentication and CSR generation #34
base: main
Are you sure you want to change the base?
Conversation
agent/yubiagent/slot.go
Outdated
} | ||
|
||
// RegisterCSR registers the given certificate signing request for the key slot. | ||
func (s *SlotAgent) RegisterCSR(csr *proto.SSHCertificateSigningRequest) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not quite sure why we need to keep the CSR
. Can you provide use cases?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need both CSR
and AddCertsToAgent
in struct slot
, because the struct implements the interface csr.AgentKey
. In this way, gensign main logic could extract all the CSRs for a key pair (or a key slot), sign them, and add the signed certificates to the corresponding agent.
for _, agentKey := range csrAgentKeys {
var (
certs []ssh.PublicKey
comments []string
)
for _, csr := range agentKey.CSRs() {
cert, comment, err := signer.Sign(ctx, csr)
if err != nil {
return fmt.Errorf("failed to sign CSR: %v", err)
}
certs = append(certs, cert...)
comments = append(comments, comment...)
}
err = agentKey.AddCertsToAgent(certs, comments)
if err != nil {
return fmt.Errorf("failed to add certificates into the agent: %v", err)
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To me, it feels like we probably need to review the design. Now, it is more like we need those methods exported because the implementation requires this to do so, not the methods is available to the struct or object.
For more specific, an Yubikey PIV slot can contain private key, and certificate but not CSRs. It doesn't make sense the retrieve it from the agent just because the implementation needs it. Similar, the ssh-agent doesn't hold the CSRs.
Also, allow a slot to retrieve its agent might be helpful in implementation, but doesn't make sense to expose it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Checking the Handler interface
It probably will make more sense to just pass the csr.Signer
into the handler to sign the certificate and store into the agent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Per discussion, the new interface will be like:
type Handler interface {
Name() string
Authenticate(params *csr.ReqParam) error
Sign(signer, param) error // 1. Gen CSR, 2. Sign, 3. Add into agent
}
agent/yubiagent/slot.go
Outdated
} | ||
|
||
// Agent returns the yubiagent. | ||
func (s *SlotAgent) Agent() YubiAgent { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why we want to export this? Can you provide use cases?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are 2 use cases:
- During ssh key challenge, we will need the agent of that key slot to invoke "Sign()"
https://github.com/theparanoids/ysshra/blob/main/agent/ssh/agent.go#L74-L85 - During attestation, I want to use the same agent of that key slot to fetch the f9 certificate.
f9Cert, err := a.slot.Agent().ReadSlot("f9")
For (2), it could be eliminated by creating a slot object for f9. For (1), I don't like to expose another function Sign()
for struct Slot
. Thus, I expose Agent()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't sound right. It make more sense to implement Sign()
for a Slot
and for the f9, it should be hold inside the struct
type authn struct {
attest *yubiagnet.Slot
slotAgent *yubiagent.Slot
conf *conf
}
// but now it needs 8 decimal digits. | ||
// For those old yubikeys with serial numbers of 7 decimal digits, | ||
// the file name of the corresponding f9 cert is prepended with a `0`. | ||
if len(f9SerialNumStr) < 8 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we prepend 8 - len(f9SerialNumStr)
0
s instead of assuming the old ones to be 7 digit long and only prepending one 0
?
default: | ||
return false | ||
} | ||
// ed25519 is non-supported key algo for now. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ed25519
is supported by yubikey but ysshra doesn't yet support it, correct? If so, can we add a todo here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to https://support.yubico.com/hc/en-us/articles/360013647820-YubiKey-4C, it is not supported in PIV mode.
switch pk.Size() * 8 { | ||
case 2048: | ||
return true | ||
default: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
any reason RSA 4096 and 8192 is not supported?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to https://support.yubico.com/hc/en-us/articles/360013647820-YubiKey-4C, it is not supported in PIV mode.
// NOTE: The following id is the touch policy stored in attestation certificate. | ||
// Refer: https://developers.yubico.com/PIV/Introduction/PIV_attestation.html | ||
if ext.Id.String() == "1.3.6.1.4.1.41482.3.8" { | ||
touch = keyid.TouchPolicy(ext.Value[1]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
need a nil check for ext.Value
?
|
||
// VerifyF9Cert will ensure that the user is using a Yubikey that was provisioned to him or her, | ||
// rather than just any Yubikey. | ||
func VerifyF9Cert(f9CertDirPath string, f9Cert *x509.Certificate) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does it need to be public?
// Name is a unique name to identify an authentication module. | ||
Name = "f9_verify" | ||
|
||
modHexMap = "cbdefghijklnrtuv" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: modHexMap
is defined twice in two different packages.
PR defines a smartcard handler to authenticate and generate CSRs for yubikey-backed SSH certificates. PR also includes 3 authentication modules and 1 csr module, which can be plugged into the smartcard handler by setting the ysshra configuration.
A sample smartcard handler config will be like:
Notes:
slot_attest
, which will be covered in another PR.I confirm that this contribution is made under the terms of the license found in the root directory of this repository's source tree and that I have the authority necessary to make this contribution on behalf of its copyright owner.