Skip to content
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

Is there a way to store a key/secret in the dongle? #401

Closed
tarun14110 opened this issue Nov 3, 2021 · 20 comments
Closed

Is there a way to store a key/secret in the dongle? #401

tarun14110 opened this issue Nov 3, 2021 · 20 comments
Assignees
Labels
question Further information is requested

Comments

@tarun14110
Copy link

Is there an API in the OpenSK that I can use to store a secret string mapped to a username and retrieve it later on?

If not, can I exploit the FIDO register call to store a secret string mapped to a username? Is there any field in the FIDO2 protocol that is stored on the authenticator and is returned during authentication? I need it for the research prototype, so any hack/ideas would help.

@kaczmarczyck
Copy link
Collaborator

Hi! Happy to hear you want to use OpenSK as a research platform!

There are no commands / primitives outside of the regular FIDO commands. During authentication, the only returned strings are inside the User Entity (see specification, under response structure). If you want to use that, make sure to

  • create a resident key (rk=True) and
  • use user verification (uv=True) so the User Entity is not filtered from the output for privacy reasons.

But, since you said "secret" string, that depends on how secret you want it to be. It is stored on hardware, so you can unplug OpenSK to carry it around, but user name and user display name are not considered secrets.

Nothing stops you from encrypting that string, of course. And then the username is some unreadable or encoded bytestring. One thing you might want to look into is the HMAC-secret extension. It allows you to do some symmetric crypto on device, maybe that is what you are looking for?

To give you a better answer, I'd have to understand your requirements better.

@kaczmarczyck kaczmarczyck self-assigned this Nov 3, 2021
@kaczmarczyck kaczmarczyck added the question Further information is requested label Nov 3, 2021
@tarun14110
Copy link
Author

Hi! Thanks for the quick reply.

Research context: Currently no major web services provide passwordless authentication. For a user study, we are trying to imitate the passwordless authentication behavior for a couple of popular websites. For that we want to store the user's website password in the security key and retrieve it later when user plugs in the security key and taps it. We are using a chrome extension to handle the UI at the browser end.

I was playing with user entity, but couldn't get it work. I didn't realize it requires uv=true. Because we want to use regular security keys without any user verification built-in, i think this option is not going to work for us? Is there a way to store and retrieve a password string without using uv?

As far as I understand HMAC-secret extension, only allows you to generate a new secret key. You cannot store a pre-determined password, right?

In case we do not find something that I can directly use, I am planning to introduce a new command in the firmware to store the passwords.

@kaczmarczyck
Copy link
Collaborator

The term uv is a bit overloaded. For OpenSK, you can set a PIN and use that for user verification. (In some contexts, uv is only about built-in user verification. To get the User Entity back, PINs are okay.)

Your understanding of HMAC-secret is correct. I thought it might be interesting if you want to encrypt the passwords that you store in the User Entity info. You definitely lose the guarantees that security keys usually offer. Plaintext on OpenSK is like a plaintext password manager that is somewhat easier to steal.

To write your own command, you have 2 choices:

  • Upgrade commands #381 is an example where I implement 2 custom commands.
  • You write an extension, and add it to Make and Get (probably harder).

You'd also have to dig into our persistent storage code to actually store the new string. The credential storage data structure is here.

@kaczmarczyck
Copy link
Collaborator

Thinking about extensions, maybe credBlob solves your problem?

The specification requires RPs to use credProtect, implying uv (in OpenSK's case, that is PIN). OpenSK itself also requires rk.

One implicit restriction is that this passwords need to be encoded with 32 Byte, but you can change that constant here.`

@tarun14110
Copy link
Author

tarun14110 commented Nov 3, 2021

thanks, @kaczmarczyck, all the suggestions are very helpful. Requiring PINS at the user end for our purpose is fine, even preferable. credBlob seems like a suitable fit. Are you familiar with an easy way to test credblob behavior from a client perspective? I was using libfido2 library from yubico, but don't see an obvious way to use credBlob there yet.
Is it fine if I leave this issue open for a day or two until I test out the credBlob idea?

@kaczmarczyck
Copy link
Collaborator

Please leave it open! credBlob is an addition from CTAP 2.1, and that isn't really used / supported in the ecosystem yet. So if you encounter any issues, feedback is appreciated. I don't know how far the progress on libfido2, but if they don't support it yet, you can send custom commands (as a last resort):

result = authenticator.send_cbor(
    COMMAND_BYTE,
    data=cbor_data,
)

@kaczmarczyck
Copy link
Collaborator

kaczmarczyck commented Nov 3, 2021

The example is taken from our configure script.

@tarun14110
Copy link
Author

tarun14110 commented Nov 7, 2021

@kaczmarczyck I have been looking into credBlob, but I don't think it is going to work for us at the moment because most browsers seemed to not have implemented the credBlob extension yet. So now I am trying to use displayName in the userEntity to store passwords for the time being. But even couldn't get that to work. Below are the registration and authentication logs. I was expecting the authenticator to return the display name during authentication.

I am getting user.id back from the authenticator during authentication. Are there any potential concerns that I need to think about before using the user.id for storing a string in there? I am using rk=True and user verification through PIN.

Registration response

{
  "type": "public-key",
  "id": "VCygN2KRdDUGMXkTaIYN2dWy6BLGMi8NzHSMfzuVaCg",
  "response": {
    "attestationObject": "o2NmbXRmcGFja2VkZ2F0dFN0bXSiY2FsZyZjc2lnWEcwRQIhAMmjRaSKjLKZOksXewFO8vqrRkm_m4kaCHSMPXqvjeZWAiAZDqDQ8mqPE_vfcK7gF513SzY0z8RLNohujuh_s3Jkr2hhdXRoRGF0YVikSZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2NFAAAALY3D0Ag40EzRrzuc8cHyHewAIFQsoDdikXQ1BjF5E2iGDdnVsugSxjIvDcx0jH87lWgopQECAyYgASFYINyj1EMmmVj8oh3YvlHcGyGQ0Wdlms6OdK6lkhvgQb9xIlggxUftXsYRl5sdqjncHPoHWL1tM6CM-gwU1X8nTcPKTno",
    "clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiTF94UnNvUkVRSm1hcjkwc3gxSk8yOGxlc0twN3ZwUngxSFVxSXhZR2RDYyIsIm9yaWdpbiI6Imh0dHBzOi8vbG9jYWxob3N0Ojg0NDMiLCJjcm9zc09yaWdpbiI6ZmFsc2UsIm90aGVyX2tleXNfY2FuX2JlX2FkZGVkX2hlcmUiOiJkbyBub3QgY29tcGFyZSBjbGllbnREYXRhSlNPTiBhZ2FpbnN0IGEgdGVtcGxhdGUuIFNlZSBodHRwczovL2dvby5nbC95YWJQZXgifQ",
    "transports": [
      "usb"
    ]
  },
  "clientExtensionResults": {
    "credProps": {
      "rk": true
    }
  },
  "_clientDataJson": {
    "type": "webauthn.create",
    "challenge": "L_xRsoREQJmar90sx1JO28lesKp7vpRx1HUqIxYGdCc",
    "origin": "https://localhost:8443",
    "crossOrigin": false,
    "other_keys_can_be_added_here": "do not compare clientDataJSON against a template. See https://goo.gl/yabPex"
  }
}

Registration Request:

{
  "username": "test1",
  "credentialNickname": "",
  "requestId": "BHHJOgaPW8LITNnQA5OdWb_mBDwgGzsmzuxhArPgDu8",
  "publicKeyCredentialCreationOptions": {
    "rp": {
      "name": "Yubico WebAuthn demo",
      "id": "localhost"
    },
    "user": {
      "name": "test1",
      "displayName": "dptest1",
      "id": "ePmBm9KjVae4BSAFiqmU2EHMvReoEpWldBcCcRxVpa8"
    },
    "challenge": "L_xRsoREQJmar90sx1JO28lesKp7vpRx1HUqIxYGdCc",
    "pubKeyCredParams": [
      {
        "alg": -7,
        "type": "public-key"
      },
      {
        "alg": -8,
        "type": "public-key"
      },
      {
        "alg": -257,
        "type": "public-key"
      }
    ],
    "excludeCredentials": [],
    "authenticatorSelection": {
      "requireResidentKey": true,
      "residentKey": "required",
      "userVerification": "preferred"
    },
    "attestation": "direct",
    "extensions": {
      "appidExclude": "https://localhost:8443",
      "credProps": true
    }
  },
  "sessionToken": "lmcur24Rej6gcZDwvEpnGZjYWVSODPRdG1aPn3AfpCU"
}

Authentication response:

{
  "type": "public-key",
  "id": "VCygN2KRdDUGMXkTaIYN2dWy6BLGMi8NzHSMfzuVaCg",
  "response": {
    "authenticatorData": "SZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2MFAAAANQ",
    "clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiWDRqbDRSUHZUMEdTNy04WlBWWVZtcDRtNmVoUmtKSU5HYm4ya0h2dFVTUSIsIm9yaWdpbiI6Imh0dHBzOi8vbG9jYWxob3N0Ojg0NDMiLCJjcm9zc09yaWdpbiI6ZmFsc2V9",
    "signature": "MEQCIAjs-4UaMsrEfbrwXZ3iiT9B0ZTZEaS6v9G9pEqd1Aj8AiBuhLesHhRr0f2bmSDcCEF38Um9egkP-AFtL7eRjBHaRw",
    "userHandle": "ePmBm9KjVae4BSAFiqmU2EHMvReoEpWldBcCcRxVpa8"
  },
  "clientExtensionResults": {
    "appid": false
  },
  "_clientDataJson": {
    "type": "webauthn.get",
    "challenge": "X4jl4RPvT0GS7-8ZPVYVmp4m6ehRkJINGbn2kHvtUSQ",
    "origin": "https://localhost:8443",
    "crossOrigin": false
  }
}

Authentication Request:

{
  "requestId": "RT2FdFgHUg593R47c2uk7JpJiLAnnO7E3PjbdCVzMuA",
  "publicKeyCredentialRequestOptions": {
    "challenge": "X4jl4RPvT0GS7-8ZPVYVmp4m6ehRkJINGbn2kHvtUSQ",
    "rpId": "localhost",
    "allowCredentials": [
      {
        "type": "public-key",
        "id": "VCygN2KRdDUGMXkTaIYN2dWy6BLGMi8NzHSMfzuVaCg",
        "transports": [
          "usb"
        ]
      }
    ],
    "userVerification": "preferred",
    "extensions": {
      "appid": "https://localhost:8443"
    }
  },
  "username": "test1"
}

@kaczmarczyck
Copy link
Collaborator

Are these logs WebAuthn or CTAP? My understanding is that you have three components:

  • Authenticator == OpenSK
  • Client == custom Chrome extension
  • RP == example on localhost

Your logs are the communication between Client and RP? Which of them are OpenSK related?

@tarun14110
Copy link
Author

tarun14110 commented Nov 8, 2021

These logs are at the client's end. Requests are sent to the authenticator and responses are received by the client from the authenticator (but are processed by the client to send to RP).
Step 1 and Step 5 are logged from https://developers.yubico.com/WebAuthn/WebAuthn_Developer_Guide/WebAuthn_Client_Registration.html. I am using chrome as my webAuthn client. So, could it be possible that chrome's webauthn client is dropping the display name that it receives from the authenticator? Should I verify it with some other client?

@kaczmarczyck
Copy link
Collaborator

I believe that OpenSK initially did send a display name, if you set one. You'd have to grab it from its response before Chrome filters it. I don't think OpenSK can fix this or the fact that browsers don't implement credBlob. If you considered a custom command, then you'd need custom logic in the client too, so that doesn't seem to help in that regard?

Concerning your question about user ID vs display name, they are not really different from OpenSK's perspective. The former is a byte string, the latter a text string. But @nuno0529 mentioned a difference in the client, and I think that RPs choose the user ID, whereas the user name and display name have more freedom for choice.

@tarun14110
Copy link
Author

Thanks for your answers. That makes a lot of sense. I'll use the user.id field in case nothing else works out.
I find out that newer versions of chrome supports credBlob, so I am back exploring credBlob like @kaczmarczyck suggested.

To register I am sending the following request from chrome console. I include the credBlob in the extension, however in the response, I get credBlob as false. Do you have any ideas why this could be happening? I am using rk and userVerfication.

credValue = new Uint8Array([1,2,3,4,5,6,7,8,9])
var publicKey = {
  challenge: new Uint8Array(16),
  rp: {
    name: "Example CORP",
    id  : "fidoalliance.org"
  },
  user: {
    id: new Uint8Array(16),
    name: "jdoe@example.com",
    displayName: "John Doe"
  },
  pubKeyCredParams: [
    {
      type: "public-key",
      alg: -7
    }
  ],
  "authenticatorSelection": {
      "requireResidentKey": true,
      "requireUserVerification": true,
      "residentKey": "required",
      "userVerification": "required"
    },
    "extensions": {
      "credBlob": credValue,
      "credProtect": 0x03,
      "credProps": true
    }
};

navigator.credentials.create({ publicKey })
  .then(function (newCredentialInfo) {
    var response = newCredentialInfo.response;
    var clientExtensionsResults = newCredentialInfo.getClientExtensionResults();
  }).catch(function (err) {
     console.error(err);
  });

clientExtensionsResults value from the authenticator:

{
    "credBlob": false,
    "credProps": {
        "rk": true
    }
}

I tried to verify that if OpenSK supports credBlob, by using authenticatorGetInfo. "Authenticator reflects amount of byte storage it supports as maxCredBlobLength parameter in authenticatorGetInfo". But I don't see it in the response from the authenticator.

./info /dev/hidraw3

proto: 0x02
major: 0x01
minor: 0x00
build: 0x00
caps: 0x05 (wink, cbor, msg)
version strings: U2F_V2, FIDO_2_0
extension strings: hmac-secret
aaguid: 8dc3d00838d04cd1af3b9cf1c1f21dec
options: rk, up, clientPin
maxmsgsiz: 1024
maxcredcntlst: 0
maxcredlen: 0
fwversion: 0x0
pin protocols: 1

@kaczmarczyck
Copy link
Collaborator

I failed to mention that credBlob is only on the develop branch of OpenSK. Sorry for that. :( stable is the CTAP 2.0 certified version, and CTAP 2.1 support was a recent addition. When switching branches, you will have to run:

./reset.sh
./setup.sh

The board name changed, too, i.e.

./deploy.py --opensk --board=nrf52840dk_opensk

You might have to erase the persistent storage due to a backwards incompatilbe change. Also be aware that reset.sh erases all uncommited changes to the OpenSK repository. Your new GetInfo response should also have FIDO_2_1_PRE in the list.

@tarun14110
Copy link
Author

I am trying to reflash the dongle using ./deploy.py --board="nrf52840_dongle_dfu" --opensk --programmer=nordicdfu. But it says fatal: Couldn't find any DFU device on your system. Do I have to reset it before reflashing it? Do you want me to open another issue for this? I think some explanation of reflashing over USB in the documentation would be helpful if it's a different process.

@kaczmarczyck
Copy link
Collaborator

I'm currently of reworking the documentation! Until that lands, let me try to help. You do need to reset some things, depending on how far you are jumping in history. To be safe, you reset both repo and storage. Be careful, the reset scripts deletes all uncommited changes!

./reset.sh
./setup.sh
./deploy.py ... --erase_storage
./tools/configure.py \
        --certificate=crypto_data/opensk_cert.pem \
        --private-key=crypto_data/opensk.key

I don't think this explains your error message though. Your device is not even detected. I had to press the tiny reset button that is hard to see and operate, located next to the actual user button. Usually, the idea is to the the device into DFU mode. My dongle indicates it is ready to be flashed with a slow red blink.

@kaczmarczyck
Copy link
Collaborator

To be more precise with the deploy instructions: First --erase_storage, then --opensk:

./deploy.py --board="nrf52840_dongle_dfu" --programmer=nordicdfu --erase_storage
./deploy.py --board="nrf52840_dongle_dfu" --programmer=nordicdfu --opensk

@tarun14110
Copy link
Author

Thanks, @kaczmarczyck. That worked. I still cannot retrieve the credBlob during authentication, but I found that it's an issue with Chrome browser implementation. I am following up with them on this.

@kaczmarczyck
Copy link
Collaborator

Awesome! If you don't mind, I'd appreciate a quick update on a later stage of your project. Some FIDO 2.1 features are currently still not used much, and any real world feedback is useful.
@tarun14110

@tarun14110
Copy link
Author

Sure! We decided to use OpenSK for our research going forward. we would be happy to give the feedbacks we have.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants