Skip to content

Commit 719bbd6

Browse files
authored
Merge pull request #441 from Yubico/dennisdyallo/docs-fix-inconsistencies
docs: Address inconsistencies and obsolete class references
2 parents 7a186de + 4962308 commit 719bbd6

18 files changed

Lines changed: 196 additions & 118 deletions

docs/users-manual/application-fido2/fido2-authenticator-config.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ Or you can check the "setMinPINLength" option.
5151

5252
```csharp
5353
// Get the "setMinPINLength" option to know if it is possible to set the minimum PIN length.
54-
OptionValue setMinPinLenValue = AuthenticatorInfo.GetOptionValue(AuthenticatorOptions.setMinPINLength);
54+
OptionValue setMinPinLenValue = fido2Session.AuthenticatorInfo.GetOptionValue(AuthenticatorOptions.setMinPINLength);
5555

5656
// If the option is True, then it is supported, it is possible to set the min PIN length.
5757
if (setMinPinLenValue == OptionValue.True)
@@ -116,7 +116,7 @@ its state before toggling.
116116
}
117117
// If this option is False, then it is supported and the YubiKey is not currently set
118118
// to always require UV. If you want it set to be always require UV, then toggle.
119-
if (alwaysIvValue == OptionValue.False)
119+
if (alwaysUvValue == OptionValue.False)
120120
{
121121
return fido2Session.TryToggleAlwaysUv();
122122
}
@@ -171,7 +171,7 @@ KeyCollector. If you don't want to build a
171171
authenticatorConfig methods. For example:
172172

173173
```csharp
174-
bool isVerified = fido2Session.TryVerifyPin(PinUvAuthTokenPemissions.AuthenticatorConfiguration);
174+
bool isVerified = fido2Session.TryVerifyPin(PinUvAuthTokenPermissions.AuthenticatorConfiguration);
175175
```
176176

177177
## Enable enterprise attestation

docs/users-manual/application-fido2/fido2-pin.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ this.
204204

205205
```csharp
206206
char[] pinChars = CollectPin();
207+
// Note: string cannot be securely wiped from memory — see tradeoff discussion above.
207208
string pinAsString = new string(pinChars);
208209
string normalizedPin = pinAsString.Normalize();
209210
byte[] utf8Pin = Encoding.UTF8.GetBytes(normalizedPin);

docs/users-manual/application-oath/oath-credentials.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ The URI specification [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986).
136136
If you are unable to capture the QR code and use a URI string, you can manually create the credential by adding the
137137
account information. The Issuer is recommended, but not required.
138138

139-
```
139+
```csharp
140140
// create TOTP credential
141141
var credential = new Credential {
142142
Issuer = "Yubico",
@@ -146,7 +146,7 @@ var credential = new Credential {
146146
Digits = 6,
147147
Secret = "HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ",
148148
RequireTouch = false
149-
}
149+
};
150150

151151
// create HOTP credential
152152
var credential = new Credential {
@@ -157,5 +157,5 @@ var credential = new Credential {
157157
Counter = 0,
158158
Secret = "HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ",
159159
RequireTouch = false
160-
}
160+
};
161161
```

docs/users-manual/application-oath/oath-session.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ oathSession.RenameCredential(credentialTotp, "Test", "example@test.com");
277277
// Or
278278
279279
// Pass Issuer, AccountName, Type and Period of the credential you want to rename, as well as the new Issuer and AccountName.
280-
Credential credential = RemoveCredential(
280+
Credential credential = oathSession.RenameCredential(
281281
"Yubico",
282282
"test@yubico.com",
283283
"Test",
@@ -286,7 +286,7 @@ Credential credential = RemoveCredential(
286286
CredentialPeriod.Period60);
287287

288288
// Pass just the current and new Issuer and AccountName if the credential has TOTP type and default period.
289-
Credential credential = RemoveCredential(
289+
Credential credential = oathSession.RenameCredential(
290290
"Yubico",
291291
"test@yubico.com",
292292
"Test",

docs/users-manual/application-otp/how-to-program-a-challenge-response-credential.md

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,22 @@ the button during a challenge-response operation.
107107
```C#
108108
using (OtpSession otp = new OtpSession(yubiKey))
109109
{
110-
// The secret key, hmacKey, was set elsewhere.
111-
otp.ConfigureChallengeResponse(Slot.ShortPress)
112-
.UseHmacSha1()
113-
.UseKey(hmacKey)
114-
.UseButton()
115-
.Execute();
110+
try
111+
{
112+
// The secret key, hmacKey, was set elsewhere.
113+
otp.ConfigureChallengeResponse(Slot.ShortPress)
114+
.UseHmacSha1()
115+
.UseKey(hmacKey)
116+
.UseButton()
117+
.Execute();
118+
119+
// Share the secret key with the validation server (if you haven't already)
120+
// before clearing.
121+
}
122+
finally
123+
{
124+
CryptographicOperations.ZeroMemory(hmacKey.Span);
125+
}
116126
}
117127
```
118128

@@ -124,13 +134,21 @@ credential. This configuration uses the Yubico OTP algorithm and a randomly gene
124134
```C#
125135
using (OtpSession otp = new OtpSession(yubiKey))
126136
{
127-
//Don't forget to share the secret key with the validation server before clearing it from memory.
128137
Memory<byte> secretKey = new byte[ConfigureYubicoOtp.KeySize];
129138

130-
otp.ConfigureChallengeResponse(Slot.LongPress)
131-
.UseYubiOtp()
132-
.GenerateKey(secretKey)
133-
.Execute();
139+
try
140+
{
141+
otp.ConfigureChallengeResponse(Slot.LongPress)
142+
.UseYubiOtp()
143+
.GenerateKey(secretKey)
144+
.Execute();
145+
146+
// Share the secret key with the validation server before clearing.
147+
}
148+
finally
149+
{
150+
CryptographicOperations.ZeroMemory(secretKey.Span);
151+
}
134152
}
135153
```
136154

docs/users-manual/application-otp/how-to-program-a-yubico-otp-credential.md

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,22 @@ credential as follows:
5151
```C#
5252
using (OtpSession otp = new OtpSession(yKey))
5353
{
54-
// privateId and aesKey are Memory<byte> references.
55-
otp.ConfigureYubicoOtp(Slot.ShortPress)
56-
.UseSerialNumberAsPublicId()
57-
.UsePrivateId(privateId)
58-
.UseKey(aesKey)
59-
.Execute();
54+
try
55+
{
56+
// privateId and aesKey are Memory<byte> references.
57+
otp.ConfigureYubicoOtp(Slot.ShortPress)
58+
.UseSerialNumberAsPublicId()
59+
.UsePrivateId(privateId)
60+
.UseKey(aesKey)
61+
.Execute();
62+
63+
// Do whatever is needed with privateId and aesKey before clearing them from memory.
64+
}
65+
finally
66+
{
67+
CryptographicOperations.ZeroMemory(privateId.Span);
68+
CryptographicOperations.ZeroMemory(aesKey.Span);
69+
}
6070
}
6171
```
6272

@@ -71,13 +81,21 @@ using (OtpSession otp = new OtpSession(yKey))
7181
Memory<byte> privateId = new byte[ConfigureYubicoOtp.PrivateIdentifierSize];
7282
Memory<byte> aesKey = new byte[ConfigureYubicoOtp.KeySize];
7383

74-
otp.ConfigureYubicoOtp(Slot.ShortPress)
75-
.UseSerialNumberAsPublicId()
76-
.GeneratePrivateId(privateId)
77-
.GenerateKey(aesKey)
78-
.Execute();
79-
80-
// Do whatever is needed with privateId and aesKey, and clear them.
84+
try
85+
{
86+
otp.ConfigureYubicoOtp(Slot.ShortPress)
87+
.UseSerialNumberAsPublicId()
88+
.GeneratePrivateId(privateId)
89+
.GenerateKey(aesKey)
90+
.Execute();
91+
92+
// Do whatever is needed with privateId and aesKey before clearing them from memory.
93+
}
94+
finally
95+
{
96+
CryptographicOperations.ZeroMemory(privateId.Span);
97+
CryptographicOperations.ZeroMemory(aesKey.Span);
98+
}
8199
}
82100
```
83101

docs/users-manual/application-otp/how-to-program-an-hotp-credential.md

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,18 @@ using (OtpSession otp = new OtpSession(yubiKey))
5757
{
5858
ReadOnlyMemory<byte> hmacKey = new byte[ConfigureHotp.HmacKeySize] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
5959

60-
otp.ConfigureHotp(Slot.LongPress)
61-
.UseKey(hmacKey)
62-
.Execute();
60+
try
61+
{
62+
otp.ConfigureHotp(Slot.LongPress)
63+
.UseKey(hmacKey)
64+
.Execute();
65+
66+
// Share hmacKey with the validation server before clearing.
67+
}
68+
finally
69+
{
70+
CryptographicOperations.ZeroMemory(hmacKey.Span);
71+
}
6372
}
6473
```
6574

@@ -70,9 +79,18 @@ using (OtpSession otp = new OtpSession(yubiKey))
7079
{
7180
Memory<byte> hmacKey = new byte[ConfigureHotp.HmacKeySize];
7281

73-
otp.ConfigureHotp(Slot.LongPress)
74-
.GenerateKey(hmacKey)
75-
.Execute();
82+
try
83+
{
84+
otp.ConfigureHotp(Slot.LongPress)
85+
.GenerateKey(hmacKey)
86+
.Execute();
87+
88+
// Share hmacKey with the validation server before clearing.
89+
}
90+
finally
91+
{
92+
CryptographicOperations.ZeroMemory(hmacKey.Span);
93+
}
7694
}
7795
```
7896

@@ -102,11 +120,20 @@ using (OtpSession otp = new OtpSession(yubiKey))
102120
{
103121
Memory<byte> hmacKey = new byte[ConfigureHotp.HmacKeySize];
104122

105-
otp.ConfigureHotp(Slot.LongPress)
106-
.UseInitialMovingFactor(16)
107-
.GenerateKey(hmacKey)
108-
.Use8Digits()
109-
.Execute();
123+
try
124+
{
125+
otp.ConfigureHotp(Slot.LongPress)
126+
.UseInitialMovingFactor(16)
127+
.GenerateKey(hmacKey)
128+
.Use8Digits()
129+
.Execute();
130+
131+
// Share hmacKey with the validation server before clearing.
132+
}
133+
finally
134+
{
135+
CryptographicOperations.ZeroMemory(hmacKey.Span);
136+
}
110137
}
111138
```
112139

docs/users-manual/application-otp/how-to-slot-access-codes.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,11 @@ using (OtpSession otp = new OtpSession(yubiKey))
9999
}
100100
```
101101

102+
> [!NOTE]
103+
> In production code, clear sensitive buffers such as access codes and HMAC keys after use with
104+
> `CryptographicOperations.ZeroMemory()`. See [Sensitive Data](../sdk-programming-guide/sensitive-data.md)
105+
> for details.
106+
102107
### Example: modify a slot access code
103108

104109
To modify a slot's access code, you must provide the current access code

docs/users-manual/application-piv/access-control.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ For example, suppose you have some code to generate a key pair.
3838
using (var pivSession = new PivSession(yubiKeyToUse))
3939
{
4040
pivSession.KeyCollector = SomeKeyCollector;
41-
PivPublicKey publicKey = pivSession.GenerateKeyPair(
41+
IPublicKey publicKey = pivSession.GenerateKeyPair(
4242
PivSlot.Authentication,
43-
PivAlgorithm.EccP256,
43+
KeyType.ECP256,
4444
PivPinPolicy.Once,
4545
PivTouchPolicy.Once);
4646
}

docs/users-manual/application-piv/attestation.md

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ before deployment.
280280
There is a method in the `PivSession` class to replace the attestation key and cert.
281281

282282
```csharp
283-
public void ReplaceAttestationKeyAndCertificate(PivPrivateKey privateKey, X509Certificate2 certificate)
283+
public void ReplaceAttestationKeyAndCertificate(IPrivateKey privateKey, X509Certificate2 certificate)
284284
```
285285

286286
If you use this method to replace the key and cert, it will check the certificate to make
@@ -301,28 +301,31 @@ class is not one you should use with sensitive data, so we present this techniqu
301301
using System.Security.Cryptography;
302302
using System.Security.Cryptography.X509Certificates;
303303

304-
private static bool IsMatchingKeyAndCert(PivPrivateKey privateKey, X509Certificate2 certificate)
304+
private static bool IsMatchingKeyAndCert(IPrivateKey privateKey, X509Certificate2 certificate)
305305
{
306-
if (privateKey.Algorithm == PivAlgorithm.Rsa2048)
306+
if (privateKey is RSAPrivateKey rsaPrivateKey)
307307
{
308-
return IsMatchingKeyAndCertRsa((PivRsaPrivateKey)privateKey, (RSA)certificate.PublicKey.Key);
308+
return IsMatchingKeyAndCertRsa(rsaPrivateKey, (RSA)certificate.PublicKey.Key);
309309
}
310310

311-
return IsMatchingKeyAndCertEcc((PivEccPrivateKey)privateKey, (byte[])certificate.PublicKey.EncodedKeyValue);
311+
if (privateKey is ECPrivateKey ecPrivateKey)
312+
{
313+
return IsMatchingKeyAndCertEcc(ecPrivateKey, (byte[])certificate.PublicKey.EncodedKeyValue);
314+
}
315+
316+
throw new ArgumentException("Unsupported key type");
312317
}
313318

314-
private static bool IsMatchingKeyAndCertRsa(PivRsaPrivateKey privateKey, RSA publicKey)
319+
private static bool IsMatchingKeyAndCertRsa(RSAPrivateKey privateKey, RSA publicKey)
315320
{
316-
bool returnValue = isValidCert;
317-
318321
// In order to build a System.Security.Cryptography.RSA object
319322
// that contains the private key, we must provide all possible
320323
// components: modulus, public exponent, private exponent, CRT
321324
// info.
322325
// We have everything needed from the publicKey (an RSA object)
323-
// and privateKey (a PivRsaPrivateKey object) except for the
326+
// and privateKey (an RSAPrivateKey object) except for the
324327
// private exponent. If you have the CRT info, you don't need the
325-
// private exponent, so the PivRsaPrivateKey class doesn't keep
328+
// private exponent, so the RSAPrivateKey class doesn't keep
326329
// it (and the YubiKey itself does not keep it).
327330
// But in order to build the RSA private key-containing object we
328331
// need to obtain the private exponent. Except we don't really.
@@ -333,6 +336,7 @@ private static bool IsMatchingKeyAndCertRsa(PivRsaPrivateKey privateKey, RSA pub
333336
// using an arbitrary private exponent.
334337
335338
RSAParameters publicParams = publicKey.ExportParameters(false);
339+
RSAParameters keyParams = privateKey.Parameters;
336340
byte[] fakeExponent = new byte[publicParams.Modulus.Length];
337341
byte[] modCopy = new byte[publicParams.Modulus.Length];
338342
byte[] expCopy = new byte[publicParams.Exponent.Length];
@@ -358,11 +362,11 @@ private static bool IsMatchingKeyAndCertRsa(PivRsaPrivateKey privateKey, RSA pub
358362
try
359363
{
360364
rsaParams.D = fakeExponent;
361-
rsaParams.DP = privateKey.ExponentP.ToArray();
362-
rsaParams.DQ = privateKey.ExponentQ.ToArray();
363-
rsaParams.InverseQ = privateKey.Coefficient.ToArray();
364-
rsaParams.P = privateKey.PrimeP.ToArray();
365-
rsaParams.Q = privateKey.PrimeQ.ToArray();
365+
rsaParams.DP = keyParams.DP;
366+
rsaParams.DQ = keyParams.DQ;
367+
rsaParams.InverseQ = keyParams.InverseQ;
368+
rsaParams.P = keyParams.P;
369+
rsaParams.Q = keyParams.Q;
366370
rsaParams.Modulus = modCopy;
367371
rsaParams.Exponent = expCopy;
368372

@@ -385,11 +389,9 @@ private static bool IsMatchingKeyAndCertRsa(PivRsaPrivateKey privateKey, RSA pub
385389
}
386390
}
387391

388-
private static bool IsMatchingKeyAndCertEcc(PivEccPrivateKey privateKey, byte[] publicKey)
392+
private static bool IsMatchingKeyAndCertEcc(ECPrivateKey privateKey, byte[] publicKey)
389393
{
390-
bool returnValue = false;
391-
392-
ECCurve eccCurve = privateKey.Algorithm == PivAlgorithm.EccP256 ?
394+
ECCurve eccCurve = privateKey.KeyType == KeyType.ECP256 ?
393395
ECCurve.CreateFromValue("1.2.840.10045.3.1.7") :
394396
ECCurve.CreateFromValue("1.3.132.0.34");
395397

@@ -407,7 +409,7 @@ private static bool IsMatchingKeyAndCertEcc(PivEccPrivateKey privateKey, byte[]
407409
Array.Copy(publicKey, 1 + coordLength, yCoord, 0, coordLength);
408410
eccParams.Q.X = xCoord;
409411
eccParams.Q.Y = yCoord;
410-
eccParams.D = privateKey.PrivateValue.ToArray();
412+
eccParams.D = privateKey.Parameters.D;
411413

412414
// To determine if the public key in the cert is the partner
413415
// to the private key, sign random data using that private

0 commit comments

Comments
 (0)