4014 stories
·
4 followers

Setting up SSH keys on macOS with Touch ID

1 Share

Blog post social card

In the first part of this post I’ll show a simple, secure way to create an SSH key on Mac (it’s 3 commands, including support for GitHub). In the second part I’ll dig deeper and explain what’s actually happening for the curious reader.

Macs have a built-in so-called Secure Enclave, where we can create “identities” that simply cannot be stolen (unless maybe you’ve made enemies with a nation state). Those identities are protected with Touch ID and can be used for SSH authentication. There are some great benefits about using this over traditional SSH key files:

  • The private material cannot be extracted, is never shown, cannot be stolen,
  • You get prompted whenever the identity is used,
  • No key files (like ~/.ssh/id_ed25519.pub and friends) littering the file system; and there’s no risk of mistakenly deleting them either.

This extra security will be in effect whenever you use SSH, including git-over-ssh like GitHub. It’s great that advanced security tech is available by default on some of the most widely distributed computers in the world! A few years ago stuff like this could only be found at CERN and/or in Dan Brown novels. Let’s see how it can be set up on your consumer-grade Mac.

It is essential that the human interface be designed for ease of use, so that users routinely and automatically apply the protection mechanisms correctly.

  • Saltzer and Schroeder, “The Protection of Information in Computer Systems”

Quick Setup

We’ll create a secure identity on the Secure Enclave, then tell SSH how to use it for authentication, and finally add the key to GitHub.

Step 1: create the identity that you’ll use on this Mac:

sc_auth create-ctk-identity -l ssh-key -k p-256-ne -t bio # run once to create identity

You’ll be prompted to touch “Touch ID”. Your identity is now created and saved securely (parameters are explained in the deep dive below).

Step 2: tell SSH to use the identity (when prompted for a PIN, just hit enter):

ssh-add -K -S /usr/lib/ssh-keychain.dylib # run after a reboot

From here on, SSH will know to use the identity from the Secure Enclave when connecting via SSH; it does not have a good memory so you’ll need to remind it after a reboot.

Step 3: Whenever you need to register your key to a new server (like GitHub), run this command:

ssh-add -L # run when you need the public key

If multiple identities are listed, use the line that starts with sk-ecdsa-sha2-nistp256.... It’s a shareable handle for the identity, and this is the SSH key that GitHub will ask about.

image

The output of ssh-add -L can be added as a GitHub SSH Key

That’s all you need for a super secure setup! The new identity can now be used with SSH, and you’ll be prompted for Touch ID during authentication:

git push # triggers Touch ID prompt

No one can steal your identity (well, you can’t even give it away willingly since it can’t be extracted from the Secure Enclave), but with great powers etc: if your Mac dies, so does the identity, and you’ll need to create a new one (and re-register it where necessary, like GitHub).

image

You’ll get a Touch ID prompt when git tries to authenticate with SSH

If you’re curious about how this works, read on!

Under the hood

We’ll now try to understand what happens under the hood. We’ll start with the actual identity creation in the Secure Enclave, then look at how SSH is allowed to interface with the Secure Enclave with ssh-keychain.dylib, and then try to see what happens in a complete SSH sign-in flow.

This is the result of reading posts (like this great investigation by arianvp), manual pages, and experimentation. A lot of this is undocumented, and this is the minimum information I needed to form a mental model of what’s happening and convince myself that it does, indeed, work.

Some of the command outputs below have been trimmed for legibility, I invite you to run them locally if you want the full experience!

Creating an identity on the Secure Enclave

Identities are managed with the sc_auth command (where sc_ stands for Smart Card). In Apple-speak, they are “CryptoTokenKit” identities, or CTK identities for short. Why not Smart Card Identities? What is a Smart Card? No idea! There’s a lot of weird Apple vocabulary, but in practice they’re just private keys stored on the Secure Enclave:

$ sc_auth list-ctk-identities
Key Type Public Key Hash                          Prot Label
p-256-ne 458F712F281B53C683F23FC02E69D44DAFDAA3DE bio  ssh-key

If you followed along in the Quick Setup, you should have exactly one identity here, that was created when you ran the sc_auth create-ctk-identity command. Let’s look at the create-ctk-identity command in more detail:

sc_auth create-ctk-identity -l <label> -k <key type> -t <protection>

When using the p-256-ne key type, this command creates the identity on the Secure Enclave — I’m guessing by first gathering some entropy, then generating some private key material and allocating whatever it needs for bookkeeping and ensuring it can only be accessed with your fingerprint.

The label is freeform and just a note attached to the key. The key type is a cryptographic setting (the elliptic curve used). At the time of writing, the following values are accepted: p-256|p-384|p-521|p-256-ne|p-384-ne. The -ne suffix means “Non-Extractable”, meaning the key is generated by the enclave itself and cannot be extracted from the Secure Enclave. For SSH we only need signing, which is done by (and on) the Secure Enclave itself, and at no point do we need (or want) to export the private key. The p-384 curve is not supported by (Open)SSH, so this narrows it down to p-256-ne.

Finally, protection can be either bio or none. When set to bio, using the key requires biometrics (like Touch ID). With none, the key still cannot be extracted (i.e. stolen) but programs would be able to silently use SSH; I recommend using bio, but YMMV; if you get annoyed by the Touch ID prompts whenever you git pull, you might want to use none here.

Now that we have some elusive identity on the Secure Enclave, let’s see how we can tell SSH to use it for authentication.

Translating between SSH and the Secure Enclave

There’s a bit of impedance mismatch, and ssh doesn’t know how to use the identity by default:

$ ssh -T <a href="mailto:git@github.com">git@github.com</a>
git@github.com: Permission denied (publickey).

The SSH agent cannot use the Secure Enclave identities as-is, but Apple has us covered with a small translation layer in the form of ssh-keychain.dylib, a dlopen-able library available natively on all recent macOS versions:

$ ssh-add -K -S /usr/lib/ssh-keychain.dylib
...
Resident identity added: ECDSA-SK SHA256:QZ+Cx6/AkS9sek9INtsXt6t7wuHOtA555CLJu8a8V7w

Here we’re relying on ssh-add’s built-in support for FIDO-style authenticator via the -K parameter. This lets the SSH agent know that it shouldn’t read a standard private key (for instance ~/.ssh/id_ed25519) but that it should expect the keys to be stored “externally” (for a lack of better words). With -K alone, ssh-add would look for public keys on USB devices (think YubiKey); though we can customize this behavior by registering a “security key provider” with -S <provider>. This provider should be a stateless dynamically-loadable library, which is exactly what /usr/lib/ssh-keychain.dylib is. The interface is not documented (at least not in a way I was able to meaningfully process), but we can have a look at what ssh-keychain.dylib exposes:

$ dyld_info -exports /usr/lib/ssh-keychain.dylib
/usr/lib/ssh-keychain.dylib:
    -exports:
        offset      symbol
        0x00001A2C  _C_GetFunctionList
        0x00000F30  _sk_api_version
        0x00000F38  _sk_enroll
        0x0000136C  _sk_load_resident_keys
        0x00000F40  _sk_sign

Most likely, _sk_load_resident_keys is meant to return a list of (public keys of) identities, and _sk_sign will sign a payload using a specified identity (here, resident means “residing on e.g. the Secure Enclave”).

We’ve seen how the identities can be created on the Secure Enclave, and how they can, in theory, be used by the SSH agent. Let’s put this to the test and see what happens when an SSH connection is created.

SSH Sign-in flow with the ssh-keychain provider

Let’s see what we need for authenticating to a remote SSH server. At all times, the SSH agent needs (1) a list of (public) keys that can be used to authenticate, and (2) a way to prove to a server that it has the corresponding private key for any of those keys.

When ssh-add is first called with -S <provider>, the _sk_load_resident_keys routine is called, which returns the public keys of all resident keys on the FIDO-style authenticator. Those are stored in the SSH agent (alongside their corresponding provider, namely ssh-keychain.dylib) and will later be offered as candidates to any remote SSH server we try connecting to. (Also now that the SSH agent knows about the Secure Enclave identity we created earlier, we can view its SSH-style public key with ssh-add -L.)

Let’s say an SSH connection is initiated: the remote accepts one of those public keys offered by the agent and “challenges” the client to prove its identity. The agent calls _sk_sign to create a signature with the private key (matching the accepted public key) and the challenge (roughly speaking). This will be forwarded to the Secure Enclave, prompt Touch ID, and if approved, will return a signature for the challenge. The signature is forwarded back to the server, which can confirm we — the client — have the corresponding private key.

Let’s see what this looks like in practice:

$ ssh -T <a href="mailto:git@github.com">git@github.com</a>
git@github.com: Permission denied (publickey).
$ ssh-add -K -S /usr/lib/ssh-keychain.dylib
Enter PIN for authenticator:
Resident identity added: ...
$ ssh -vvv -T <a href="mailto:git@github.com">git@github.com</a>
debug1: get_agent_identities: agent returned 1 keys
debug1: Offering public key: ssh: ECDSA-SK SHA256:QZ+Cx6/AkS9sek9INtsXt6t7wuHOtA555CLJu8a8V7w authenticator agent
debug1: Server accepts key: ssh: ECDSA-SK SHA256:QZ+Cx6/AkS9sek9INtsXt6t7wuHOtA555CLJu8a8V7w authenticator agent
debug3: sign_and_send_pubkey: signing using <a href="mailto:sk-ecdsa-sha2-nistp256@openssh.com">sk-ecdsa-sha2-nistp256@openssh.com</a> SHA256:QZ+Cx6/AkS9sek9INtsXt6t7wuHOtA555CLJu8a8V7w
<at this point, Touch ID prompt appears>
Authenticated to <a href="http://github.com" rel="nofollow">github.com</a> ([20.250.119.67]:22) using "publickey".
Hi nmattia! You've successfully authenticated, but GitHub does not provide shell access.

The ssh debug logs show that one key is offered by the agent, accepted, and then used to create a signature. After the server has verified the signature, authentication is granted (although GitHub does not provide shell access).

One note: whenever we register the identity with the SSH agent, ssh-add prompts us for a PIN. What gives? Why does entering an empty PIN work, isn’t this mighty unsafe‽

Well, no, it’s not unsafe! When we tell ssh-add to use a FIDO-style authenticator, I suspect its default behavior is to ask for a PIN as it assumes we’ll be using a USB, YubiKey-style authenticator; only we shortcut the whole thing with ssh-keychain.dylib (and the security comes not from a PIN, but from the soft skin under your fingertips; much cooler). Not great in terms of usability, but I guess it makes sense. (I have no idea what would happen if you have more than one FIDO authenticator; go support me on GitHub and I’ll buy a collection of YubiKeys to experiment).

Conclusion

Let’s recap: we can use a somewhat cryptic, poorly documented “Smart Card” tool to create a “CryptoTokenKit” identity on the “Secure Enclave”. Then, by using the poorly documented ssh-keychain.dylib, we can use said identity to generate signatures that Apple’s ssh can use. There’s no guarantee that all this missing documentation wouldn’t say “Do not use this; terribly unsafe in practice”, but hey: all this security talk by Apple, they wouldn’t lie to us, right? *spooky*

Joke aside, it’s pretty cool to have sci-fi style security modules baked into most modern devices; the more people start using them and pushing for openness, the better the support from the companies will be. We can have nice things!

Again, a lot of this was derived from this gist; highly recommend having a read and potentially asking questions in the discussion.

Let me knoworjoin the discussion if you enjoyed this article! You can also subscribe to receive updates.


Here's more on the topic of macOS:

Read the whole story
emrox
8 hours ago
reply
Hamburg, Germany
Share this story
Delete

The Future of CSS ✨

1 Share

Every year, browser vendors collaborate via the Interop project to synchronize their efforts on new HTML/CSS/JS features. This year, there’s a ton of super exciting features being considered! In this blog post, we’ll explore the CSS of the future, to get a glimpse of what we’ll soon be able to do.



Read the whole story
emrox
10 hours ago
reply
Hamburg, Germany
Share this story
Delete

The End of Rationing

1 Share

s who have vowed to build a better GitHub for agentic coding today can't seem to shake it off. Salesforce's lead/opportunity/pipeline object model from 1999 became the definition of what a CRM is. Every CRM company started since inherits it.

Read the whole story
emrox
1 day ago
reply
Hamburg, Germany
Share this story
Delete

Terminal Bench 4 Is Saturated | Hacker News

1 Share

You don't have to give it up entirely, you could grade on the interpretation they chose. Personally I'm a fan of models which seek clarification on critical ambiguities rather than barging ahead "autonomously" though.

But wow, they found a lot of issues with the benchmark.

Read the whole story
emrox
1 day ago
reply
Hamburg, Germany
Share this story
Delete

Blake Watson on the state of the industry (#note)

1 Share

Here's Blake sharing his feelings about AI, software development and where we're all heading. He wrote the article that's been on my TODO list for a while. Let me comment on some highlights.

I feel like I will be able to build things I never have been able to before, but at the same time, I have heightened fears about being replaceable or less valuable in my job. If all I’m doing is prompting an AI bot, why am I being paid so much?

100% this. I'm scared and worried that the skills I put so much time into building are worth nothing. I used to be proud of my deep platform knowledge. Turns out Claude knows more.

And on a bigger scale, "personal software" is really happening. My friends are building browser extensions and websites for their fantasy football leagues. They don't care about quality as long as it gets the job done. Occasionally they ask me things about the DOOM (DOM), which is funny and scary at the same time.

At what point does software still need someone who actually knows what they're doing? I guess we'll find out soon enough.

If you haven’t used one of these coding tools in the last six months, you probably don’t have a good idea of what they are capable of.

I admire people who are still holding out against this technology, I really do. If that's you, you rock! Unfortunately, I couldn't agree more with the statement above.

If your arguments about LLM quality and all the generated fake news (hallucinations) are based on Copilot tryouts around last Christmas, you'd better check again. Things have changed a lot.

I just have this icky feeling when I use it.

Same. I hate that I can create things without effort or understanding. I hate that there are days when I talk to agents all day. I hate that it seems like nothing matters anymore. I hate that everyone is pushing and pushing and pushing and nothing gets done.

I’m worried about being replaced, but maybe I’ll be even more valuable. [...] So I just go back and forth. I worry about it, but then I think everything will work out.

Yes. There are good weeks and then there are bad weeks.

Sometimes, I'm okay with "focusing on the outcome". Sometimes, I'm fine with the loss of the job that was my favorite thing to do. Sometimes, I have enough energy to change habits and find satisfaction and joy elsewhere.

But sometimes, man... sometimes the new world drives me nuts.

So, let's hope Blake is right and things will work out (somehow).


Reply to Stefan
Read the whole story
emrox
2 days ago
reply
Hamburg, Germany
Share this story
Delete

The terrifying liminal space between code-writer and bot-prompter

1 Share

Disclaimer: These are my own thoughts and opinions. They don’t reflect those of my employer. I’m discussing my own personal feelings about AI. I think it’s fair to say everyone is having to grapple with this tech, whether it’s how to use it or how to avoid it. The following represents a snapshot of my grappling, nothing more.


LLM coding advancements both impress and terrify me and I don’t know what I think about it or how to cope with it. I feel like I will be able to build things I never have been able to before, but at the same time, I have heightened fears about being replaceable or less valuable in my job. If all I’m doing is prompting an AI bot, why am I being paid so much?

When I work with an LLM coding harness[1] it usually makes me feel uneasy. It feels like my name is going to be attached to something I didn’t really do. Sure, I could review the code. But it’s still not my code. Constantly reviewing LLM-generated code is mentally fatiguing and is not enjoyable in the way coding is. And at a certain point, it really becomes a challenge to keep up with code review. Before long, you find yourself skimming and saying, “That seems right.”

A developer who is skilled with and/or enjoys working with this stuff would probably say you don’t need to review the code. Trust the LLM, trust the tests. As much as I hate it, I think that might actually be right. Trying to keep up pace with a bot that can spew out thousands of lines of code in minutes seems like a fool’s errand.

The models are good now. That’s the refrain I’ve been hearing for the last six months. Again, as much as I hate to admit it, I have to agree the models are much better than they were. I’m routinely impressed, particularly in the GPT models. A year ago, hallucinations seemed to be more of a problem. Nowadays, the LLM will search the internet, search the code, and run its own experiments before taking a stab at answering your questions. I don’t know if it’s the models that are that much better, or if it’s a huge improvement of the harnesses. Probably both.

You’re probably sick of hearing this, but if you haven’t used one of these coding tools in the last six months, you probably don’t have a good idea of what they are capable of.

But I hate it. Why do I hate it? I just have this icky feeling when I use it. And that’s not even considering all the other big negatives like how it kinda feels like these companies stole from everyone. Or the negative environmental effects. Or all the mindless slop that’s everywhere now.

There’s obviously a lot of doom-mongering in the industry. The companies making this stuff say AI is going to take our jobs or, I shit you not, kill everyone. So that’s… good.

But let’s assume for a moment that the worst-case scenarios aren’t true. What does software development look like in the future? I’m worried about being replaced, but maybe I’ll be even more valuable. If the cost to produce software drops, Jevons paradox says people will consume even more software. If demand for software goes up, well, I’m someone who can produce software (or begrudgingly facilitate a machine producing it). I have soft skills and insights around my technical knowledge, and maybe that continues to be valuable.

So I just go back and forth. I worry about it, but then I think everything will work out. It’s something that’s been on my mind a lot this past year. I can’t just quit tech to become a gardener. As someone with spinal muscular atrophy, some kind of knowledge work is all I can do. The government programs that I use for my daily care don’t cover 100% of my needs. Without my income, I would be very near needing to live in a nursing home.

So I’m keeping watch. I’m staying open minded and trying to find a path forward in this new world.


  1. Usually either Claude Code in the terminal or Codex via the ChatGPT app. ↩︎

Read the whole story
emrox
2 days ago
reply
Hamburg, Germany
Share this story
Delete
Next Page of Stories