Closed gnida-rada closed 2 years ago
Ping. @GregDomzalski, would it be possible to get code samples that allow me to get attestation for a certificate using .NET SDK? Currently we do it using 2 commands: yubico-piv-tool -s $slot -P $UserPin --key=$mk -a verify -a request-certificate -S $CertificateSubjectName --input=$UserPublicKeyFilePath --output=$UserCertificateRequestFilePath followed by yubico-piv-tool --action=attest --slot=$slot --output=$UserAttestationFilePath
What are the equivalents? Thanks
The team should have some bandwidth next week to take a look at this. Thanks for your patience.
So I ran openssl on the CSR files, generated both ways. And they seem to be very different. The one generated with command line tools looks like: Certificate Request: Data: Version: 0 (0x0) Subject: ... Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (2048 bit) Modulus: ... Exponent: 65537 (0x10001) Attributes: Requested Extensions: Signature Algorithm: sha256WithRSAEncryption ...
whereas the one, generated using CertificateRequest.CreateSigningRequest(new YubiKeySignatureGenerator(...)) looks like: Certificate Request: Data: Version: 0 (0x0) Subject: ... Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (2048 bit) Modulus: ... Exponent: 65537 (0x10001) Attributes: a0:00 Signature Algorithm: rsassaPss Hash Algorithm: sha256 Mask Algorithm: mgf1 with sha256 Salt Length: 0x20 Trailer Field: 0xBC (default) ...
I forwarded this thread to another one of our engineers. This is what he wrote:
It sounds like you are doing the following:
1: It seems that's no problem. You are able to generate a new key pair, right?
PivSession.GenerateKeyPair()
2: In the SDK, to create an attestation statement, use
PivSession.CreateAttestationStatement(byte slotNumber).
See the User's Manual entry for additional information on attestation,
https://docs.yubico.com/yesdk/users-manual/application-piv/attestation.html
This produces an X509Certificate2 object, a .NET class, so you'll have to look at its documentation to figure out how to get the data out in the form you want. Maybe the sample code PEM conversion code can help.
Note that you don't need to have a cert request built in order to create an attestation statement. Also, it is possible to attest keys only if they were generated by the YubiKey. If it was imported, it is not attestable.
3: I believe the solution you want is to set the RSA padding scheme in the YubiKeySignatureGenerator object as well as the CertificateRequest object.
In the sample code there is this switch statement.
slotContents.CertRequest = slotContents.Algorithm switch
{
PivAlgorithm.EccP256 => new CertificateRequest(
distinguishedName,
(ECDsa)dotNetPubKey,
HashAlgorithmName.SHA256),
PivAlgorithm.EccP384 => new CertificateRequest(
distinguishedName,
(ECDsa)dotNetPubKey,
HashAlgorithmName.SHA384),
_ => new CertificateRequest(
distinguishedName,
(RSA)dotNetPubKey,
HashAlgorithmName.SHA256,
RSASignaturePadding.Pss),
};
I believe you have changed that "Pss" to "Pkcs1".
new CertificateRequest(
distinguishedName,
(RSA)dotNetPubKey,
HashAlgorithmName.SHA256,
RSASignaturePadding.Pkcs1),
Unfortunately, that is not the only place to change it. Change it in the YubiKeySignatureGenerator constructor as well. Here is the constructor in the sample code.
public YubiKeySignatureGenerator(
PivSession pivSession,
byte slotNumber,
PivPublicKey pivPublicKey,
RSASignaturePaddingMode rsaPaddingMode = RSASignaturePaddingMode.Pss)
There is that fourth argument that has a default. In the code sample you sent, you are calling the constructor with only three arguments, so the padding scheme is the default PSS.
As it turns out, the .NET CertificateRequest class ignores the padding scheme you give it and uses whatever scheme is specified in the SignatureGenerator.
Is that the only issue you are having with the cert request (other than 76 vs. 64 characters per line and the new line characters)?
Yes, indeed, I missed that default parameter! :flushed: After I added 4th param to invocation of YubiKeySignatureGenerator constructor, things worked. Thanks a lot @GregDomzalski and "another one of our engineers", for following up and spotting my silly mistake! You rock!
In yubico-piv-tool/ykman there is 1 liner command that creates PEM-encoded cert request file. In .NET SDK it is a lot more work and, at least for me, it does not seem to work.
yubico-piv-tool -a verify-pin -a request-certificate -s -i -S -o
or:
ykman piv certificates request -P -s
with .NET SDK I'm doing something like the below (based on Yubikey .NET SDK sample code). In the end I do get a PEM encoded file. It has a little different formatting than what ykpiv gives us on macOS:
get IYubiKeyDevice using AsymmetricAlgorithm dotNetPubKey = KeyConverter.GetDotNetFromPivPublicKey(publicKey); CertificateRequest certRequest = new CertificateRequest( subjectName, (RSA)dotNetPubKey, HashAlgorithmName.SHA256, // NOTE: I am using Pkcs1 instead of PSS here because that's the padding that ykpiv is using for RSA RSASignaturePadding.Pkcs1)