PeculiarVentures / fortify-examples

Fortify enables web applications to use smart cards, local certificate stores and do certificate enrollment. This is a set of examples of how to use Fortify in your own applications.
MIT License
8 stars 5 forks source link

Filtering Certificates based on certificate ID (fortify-webcomponents) #10

Open KrishnaPG opened 3 years ago

KrishnaPG commented 3 years ago

Could not find any repo for the @peculiar/fortify-webcomponents-react hence posting it here. Not sure if this is the right place.

The peculiar-fortify-certificates web-component allows certificates to be filtered based on some matching conditions of DN name etc. We can use that web-components UI to let the user select a certificate for signing.

However, if we need to restrict the certificate list to be a specific known set of certificates based on certificateID it is not possible. This is required in cases where we need to let the user select a certificate from only a list of certificates that are previously registered/associated with the app earlier. For example, to ensure non-repudiation. We want to ensure that the user:

  1. associates a certificate (from the list of all certificates) with the app, and
  2. when required to sign a message, chooses one of the previously associated certificates

The peculiar-fortify-certificates achieves the first scenario of listing all certificates (and also filter some that match a name), but does not allow filtering based on certificate IDs that makes the second scenario possible, where we list only the set of certificates that are known to us by ID.

rmhrisk commented 3 years ago

What do you mean by certificateid?

KrishnaPG commented 3 years ago

When the web-component lists the certificates in the UI and a selection is made by the user to use one of them for signing, the web-component returns something like below, which includes certificateId:

image

I could probably be wrong, but I am hoping that this certificateId (along with the rest of the details such as providerId etc.) can be stored in a database as a means to associate a particular certificate as "belonging to a user".

Next time, when signing is required, we could ask the web-ui to filter and show only these earlier "associated" certificates (because the app only knows them as the ones that belong to that user) and let the user select one of them and use them for signing.

I am referring to certificateId shown in the above screenshot (that is returned by the web-component when user selects a certificate in the UI list), to be used for the filtering.

Not sure if this is the right way, but I hope you understand what I am trying to achieve. I do not want to show the full list (the user might have added few more certificates, but the app may not know them, and hence does not allow signing with them unless they are registered with the app first).

If this is not how it should be done (as a standard practice) and there is some other way this is usually handled, please do let me know. I am trying to ensure that the user signs with a certificate that the user previously acknowledged as belonging to him.

This is the example web-component UI I am talking about: https://codepen.io/donskov/pen/OJMPPNX image

microshine commented 3 years ago

About Fortify KeyStorage and CertificateStorage identifiers. It's a composed key <type>-<handle>-<id>.

<type> - type of storage item (eg public, private, x509, request) <handle> - hexadecimal representation of PKCS#11 object handle. It's a dynamic value and may be changed from session to session <id> - hexadecimal representation of PKCS#11 CKA_ID attribute

https://github.com/PeculiarVentures/node-webcrypto-p11/blob/cbf02e7527c98e7ef99e13bb1c4e2070d8cbabe1/src/cert.ts#L126

donskov commented 3 years ago

@KrishnaPG We added certificateIdMatch: string | RegExp for filter certificates by certificateId.

Use new version:

Successfully published:
 - @peculiar/fortify-webcomponents-react@0.2.9
 - @peculiar/fortify-webcomponents@0.13.0
KrishnaPG commented 3 years ago

Thank you @donskov That is very fast.

Wondering, how do we specify an array of ids to match? Since there could be more than one? It could be:

certificateIdMatch: [ string Array ] | RegExp

KrishnaPG commented 3 years ago

One thing that could help is: to accept a function and let the user do the filtering and sorting inside that function, returning you the filtered and sorted list. That way the web-component can allow much more customisation for how the list is displayed in the UI.

For example, I would like to display the frequently used certificates on the top in the list. This would require tracking the usage statistics of the certificates, which may be out of scope of the web-components themselves.

Hence accepting a user callback function as one of the props /parameters of the web-component can allow the user to do the required customisation based on the external app-specific requirement.

The callback function accepts a list of certificate data (supplied by the web-component) and returns a promise. That promise when resolved gives the filtered and sorted certificates list that the web-component can display in its UI.

Of course, if the callback is not specified, then the web-component can fallback to its existing filter based implementation as the default behaviour.

rmhrisk commented 3 years ago

@KrishnaPG would be great to hear about what you are using Fortify with.

KrishnaPG commented 3 years ago

Thank you @rmhrisk I am trying replace the password based authentication with Certificates. Something like a single-sign-on but with certificates.

For example:

  1. user will signup on the website with his eMail using google or any other oAuth providers. (The actual auth happens on that third-party site). If that third-party returns a valid token, we treat the user as valid.
  2. Alternately, without having to use any third party oAuth, user just enters the eMail address during the signup. The website validates the eMail address by sending a secret code, as usual. Upon confirmation of the eMail we treat the user as valid.
  3. user's email is stored in the database (and no password, since user never supplied any to us).
  4. Then the user associates some certificates with his account. <- this is where Fortify comes into picture
  5. Next time when he tries to login, he has to use any of the previously associated certificates to verify that he is the one indeed. <- once again Fortify

This may look long and convoluted process just for login, but I am trying to make this compatible with webAuthn for those who would like to use certificates rather than the FIDO devices. (Here is my earlier correspondence relating to this)

These peculiar-fortify-certificates web-components are very useful for achieving the UI for the certificates. Takes cares of the certificate-listing in the UI. If these web-components can extend their listing to the webAuthn devices also, then it will complete the spectrum (UI for web-crypto + webAuthn), and these web-components will get much wider adoption (or even become the open source standard for implementing secure login UI, much like passport etc.)

rmhrisk commented 3 years ago

Interesting.

Something I have wanted to do is to create an authentication web component that wraps the select web component. The idea is that there would be an API similar to FIDO where there is a register call that would fetch a challenge from a server that is signed by the client, and an authentication call that works the same way.

With something like this you could easily create your envisioned flow I do not have a roadmap for that at this time but it will eventually happen.

donskov commented 3 years ago

Thank you @donskov That is very fast.

Wondering, how do we specify an array of ids to match? Since there could be more than one? It could be:

certificateIdMatch: [ string Array ] | RegExp

You can use RegExp for it. For example:

new RegExp(/(id1|id2)/)

Also, we think about adding a function for allowing the use of custom filters.

Thanks!