diff --git a/docs/users-manual/application-fido2/fido2-authenticator-config.md b/docs/users-manual/application-fido2/fido2-authenticator-config.md index 08e4cd41a..5c5d66822 100644 --- a/docs/users-manual/application-fido2/fido2-authenticator-config.md +++ b/docs/users-manual/application-fido2/fido2-authenticator-config.md @@ -51,7 +51,7 @@ Or you can check the "setMinPINLength" option. ```csharp // Get the "setMinPINLength" option to know if it is possible to set the minimum PIN length. - OptionValue setMinPinLenValue = AuthenticatorInfo.GetOptionValue(AuthenticatorOptions.setMinPINLength); + OptionValue setMinPinLenValue = fido2Session.AuthenticatorInfo.GetOptionValue(AuthenticatorOptions.setMinPINLength); // If the option is True, then it is supported, it is possible to set the min PIN length. if (setMinPinLenValue == OptionValue.True) @@ -116,7 +116,7 @@ its state before toggling. } // If this option is False, then it is supported and the YubiKey is not currently set // to always require UV. If you want it set to be always require UV, then toggle. - if (alwaysIvValue == OptionValue.False) + if (alwaysUvValue == OptionValue.False) { return fido2Session.TryToggleAlwaysUv(); } @@ -171,7 +171,7 @@ KeyCollector. If you don't want to build a authenticatorConfig methods. For example: ```csharp - bool isVerified = fido2Session.TryVerifyPin(PinUvAuthTokenPemissions.AuthenticatorConfiguration); + bool isVerified = fido2Session.TryVerifyPin(PinUvAuthTokenPermissions.AuthenticatorConfiguration); ``` ## Enable enterprise attestation diff --git a/docs/users-manual/application-fido2/fido2-pin.md b/docs/users-manual/application-fido2/fido2-pin.md index a50341529..61bc9218a 100644 --- a/docs/users-manual/application-fido2/fido2-pin.md +++ b/docs/users-manual/application-fido2/fido2-pin.md @@ -204,6 +204,7 @@ this. ```csharp char[] pinChars = CollectPin(); + // Note: string cannot be securely wiped from memory — see tradeoff discussion above. string pinAsString = new string(pinChars); string normalizedPin = pinAsString.Normalize(); byte[] utf8Pin = Encoding.UTF8.GetBytes(normalizedPin); diff --git a/docs/users-manual/application-oath/oath-credentials.md b/docs/users-manual/application-oath/oath-credentials.md index a1a2b4922..d52287d1e 100644 --- a/docs/users-manual/application-oath/oath-credentials.md +++ b/docs/users-manual/application-oath/oath-credentials.md @@ -136,7 +136,7 @@ The URI specification [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986). If you are unable to capture the QR code and use a URI string, you can manually create the credential by adding the account information. The Issuer is recommended, but not required. -``` +```csharp // create TOTP credential var credential = new Credential { Issuer = "Yubico", @@ -146,7 +146,7 @@ var credential = new Credential { Digits = 6, Secret = "HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ", RequireTouch = false -} +}; // create HOTP credential var credential = new Credential { @@ -157,5 +157,5 @@ var credential = new Credential { Counter = 0, Secret = "HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ", RequireTouch = false -} +}; ``` diff --git a/docs/users-manual/application-oath/oath-session.md b/docs/users-manual/application-oath/oath-session.md index a452ebf8a..0a56cd7fc 100644 --- a/docs/users-manual/application-oath/oath-session.md +++ b/docs/users-manual/application-oath/oath-session.md @@ -277,7 +277,7 @@ oathSession.RenameCredential(credentialTotp, "Test", "example@test.com"); // Or // Pass Issuer, AccountName, Type and Period of the credential you want to rename, as well as the new Issuer and AccountName. -Credential credential = RemoveCredential( +Credential credential = oathSession.RenameCredential( "Yubico", "test@yubico.com", "Test", @@ -286,7 +286,7 @@ Credential credential = RemoveCredential( CredentialPeriod.Period60); // Pass just the current and new Issuer and AccountName if the credential has TOTP type and default period. -Credential credential = RemoveCredential( +Credential credential = oathSession.RenameCredential( "Yubico", "test@yubico.com", "Test", diff --git a/docs/users-manual/application-otp/how-to-program-a-challenge-response-credential.md b/docs/users-manual/application-otp/how-to-program-a-challenge-response-credential.md index d1508e4d5..7011e9e66 100644 --- a/docs/users-manual/application-otp/how-to-program-a-challenge-response-credential.md +++ b/docs/users-manual/application-otp/how-to-program-a-challenge-response-credential.md @@ -107,12 +107,22 @@ the button during a challenge-response operation. ```C# using (OtpSession otp = new OtpSession(yubiKey)) { - // The secret key, hmacKey, was set elsewhere. - otp.ConfigureChallengeResponse(Slot.ShortPress) - .UseHmacSha1() - .UseKey(hmacKey) - .UseButton() - .Execute(); + try + { + // The secret key, hmacKey, was set elsewhere. + otp.ConfigureChallengeResponse(Slot.ShortPress) + .UseHmacSha1() + .UseKey(hmacKey) + .UseButton() + .Execute(); + + // Share the secret key with the validation server (if you haven't already) + // before clearing. + } + finally + { + CryptographicOperations.ZeroMemory(hmacKey.Span); + } } ``` @@ -124,13 +134,21 @@ credential. This configuration uses the Yubico OTP algorithm and a randomly gene ```C# using (OtpSession otp = new OtpSession(yubiKey)) { - //Don't forget to share the secret key with the validation server before clearing it from memory. Memory secretKey = new byte[ConfigureYubicoOtp.KeySize]; - otp.ConfigureChallengeResponse(Slot.LongPress) - .UseYubiOtp() - .GenerateKey(secretKey) - .Execute(); + try + { + otp.ConfigureChallengeResponse(Slot.LongPress) + .UseYubiOtp() + .GenerateKey(secretKey) + .Execute(); + + // Share the secret key with the validation server before clearing. + } + finally + { + CryptographicOperations.ZeroMemory(secretKey.Span); + } } ``` diff --git a/docs/users-manual/application-otp/how-to-program-a-yubico-otp-credential.md b/docs/users-manual/application-otp/how-to-program-a-yubico-otp-credential.md index 3928ff771..f85afb6aa 100644 --- a/docs/users-manual/application-otp/how-to-program-a-yubico-otp-credential.md +++ b/docs/users-manual/application-otp/how-to-program-a-yubico-otp-credential.md @@ -51,12 +51,22 @@ credential as follows: ```C# using (OtpSession otp = new OtpSession(yKey)) { - // privateId and aesKey are Memory references. - otp.ConfigureYubicoOtp(Slot.ShortPress) - .UseSerialNumberAsPublicId() - .UsePrivateId(privateId) - .UseKey(aesKey) - .Execute(); + try + { + // privateId and aesKey are Memory references. + otp.ConfigureYubicoOtp(Slot.ShortPress) + .UseSerialNumberAsPublicId() + .UsePrivateId(privateId) + .UseKey(aesKey) + .Execute(); + + // Do whatever is needed with privateId and aesKey before clearing them from memory. + } + finally + { + CryptographicOperations.ZeroMemory(privateId.Span); + CryptographicOperations.ZeroMemory(aesKey.Span); + } } ``` @@ -71,13 +81,21 @@ using (OtpSession otp = new OtpSession(yKey)) Memory privateId = new byte[ConfigureYubicoOtp.PrivateIdentifierSize]; Memory aesKey = new byte[ConfigureYubicoOtp.KeySize]; - otp.ConfigureYubicoOtp(Slot.ShortPress) - .UseSerialNumberAsPublicId() - .GeneratePrivateId(privateId) - .GenerateKey(aesKey) - .Execute(); - - // Do whatever is needed with privateId and aesKey, and clear them. + try + { + otp.ConfigureYubicoOtp(Slot.ShortPress) + .UseSerialNumberAsPublicId() + .GeneratePrivateId(privateId) + .GenerateKey(aesKey) + .Execute(); + + // Do whatever is needed with privateId and aesKey before clearing them from memory. + } + finally + { + CryptographicOperations.ZeroMemory(privateId.Span); + CryptographicOperations.ZeroMemory(aesKey.Span); + } } ``` diff --git a/docs/users-manual/application-otp/how-to-program-an-hotp-credential.md b/docs/users-manual/application-otp/how-to-program-an-hotp-credential.md index bcdcaf552..a797f1843 100644 --- a/docs/users-manual/application-otp/how-to-program-an-hotp-credential.md +++ b/docs/users-manual/application-otp/how-to-program-an-hotp-credential.md @@ -57,9 +57,18 @@ using (OtpSession otp = new OtpSession(yubiKey)) { ReadOnlyMemory 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, }; - otp.ConfigureHotp(Slot.LongPress) - .UseKey(hmacKey) - .Execute(); + try + { + otp.ConfigureHotp(Slot.LongPress) + .UseKey(hmacKey) + .Execute(); + + // Share hmacKey with the validation server before clearing. + } + finally + { + CryptographicOperations.ZeroMemory(hmacKey.Span); + } } ``` @@ -70,9 +79,18 @@ using (OtpSession otp = new OtpSession(yubiKey)) { Memory hmacKey = new byte[ConfigureHotp.HmacKeySize]; - otp.ConfigureHotp(Slot.LongPress) - .GenerateKey(hmacKey) - .Execute(); + try + { + otp.ConfigureHotp(Slot.LongPress) + .GenerateKey(hmacKey) + .Execute(); + + // Share hmacKey with the validation server before clearing. + } + finally + { + CryptographicOperations.ZeroMemory(hmacKey.Span); + } } ``` @@ -102,11 +120,20 @@ using (OtpSession otp = new OtpSession(yubiKey)) { Memory hmacKey = new byte[ConfigureHotp.HmacKeySize]; - otp.ConfigureHotp(Slot.LongPress) - .UseInitialMovingFactor(16) - .GenerateKey(hmacKey) - .Use8Digits() - .Execute(); + try + { + otp.ConfigureHotp(Slot.LongPress) + .UseInitialMovingFactor(16) + .GenerateKey(hmacKey) + .Use8Digits() + .Execute(); + + // Share hmacKey with the validation server before clearing. + } + finally + { + CryptographicOperations.ZeroMemory(hmacKey.Span); + } } ``` diff --git a/docs/users-manual/application-otp/how-to-slot-access-codes.md b/docs/users-manual/application-otp/how-to-slot-access-codes.md index 6d06222c7..d0fef15a6 100644 --- a/docs/users-manual/application-otp/how-to-slot-access-codes.md +++ b/docs/users-manual/application-otp/how-to-slot-access-codes.md @@ -99,6 +99,11 @@ using (OtpSession otp = new OtpSession(yubiKey)) } ``` +> [!NOTE] +> In production code, clear sensitive buffers such as access codes and HMAC keys after use with +> `CryptographicOperations.ZeroMemory()`. See [Sensitive Data](../sdk-programming-guide/sensitive-data.md) +> for details. + ### Example: modify a slot access code To modify a slot's access code, you must provide the current access code diff --git a/docs/users-manual/application-piv/access-control.md b/docs/users-manual/application-piv/access-control.md index f01642617..13eab7b46 100644 --- a/docs/users-manual/application-piv/access-control.md +++ b/docs/users-manual/application-piv/access-control.md @@ -38,9 +38,9 @@ For example, suppose you have some code to generate a key pair. using (var pivSession = new PivSession(yubiKeyToUse)) { pivSession.KeyCollector = SomeKeyCollector; - PivPublicKey publicKey = pivSession.GenerateKeyPair( + IPublicKey publicKey = pivSession.GenerateKeyPair( PivSlot.Authentication, - PivAlgorithm.EccP256, + KeyType.ECP256, PivPinPolicy.Once, PivTouchPolicy.Once); } diff --git a/docs/users-manual/application-piv/attestation.md b/docs/users-manual/application-piv/attestation.md index 297c6336f..8fd7ada6d 100644 --- a/docs/users-manual/application-piv/attestation.md +++ b/docs/users-manual/application-piv/attestation.md @@ -280,7 +280,7 @@ before deployment. There is a method in the `PivSession` class to replace the attestation key and cert. ```csharp -public void ReplaceAttestationKeyAndCertificate(PivPrivateKey privateKey, X509Certificate2 certificate) +public void ReplaceAttestationKeyAndCertificate(IPrivateKey privateKey, X509Certificate2 certificate) ``` 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 using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; -private static bool IsMatchingKeyAndCert(PivPrivateKey privateKey, X509Certificate2 certificate) +private static bool IsMatchingKeyAndCert(IPrivateKey privateKey, X509Certificate2 certificate) { - if (privateKey.Algorithm == PivAlgorithm.Rsa2048) + if (privateKey is RSAPrivateKey rsaPrivateKey) { - return IsMatchingKeyAndCertRsa((PivRsaPrivateKey)privateKey, (RSA)certificate.PublicKey.Key); + return IsMatchingKeyAndCertRsa(rsaPrivateKey, (RSA)certificate.PublicKey.Key); } - return IsMatchingKeyAndCertEcc((PivEccPrivateKey)privateKey, (byte[])certificate.PublicKey.EncodedKeyValue); + if (privateKey is ECPrivateKey ecPrivateKey) + { + return IsMatchingKeyAndCertEcc(ecPrivateKey, (byte[])certificate.PublicKey.EncodedKeyValue); + } + + throw new ArgumentException("Unsupported key type"); } -private static bool IsMatchingKeyAndCertRsa(PivRsaPrivateKey privateKey, RSA publicKey) +private static bool IsMatchingKeyAndCertRsa(RSAPrivateKey privateKey, RSA publicKey) { - bool returnValue = isValidCert; - // In order to build a System.Security.Cryptography.RSA object // that contains the private key, we must provide all possible // components: modulus, public exponent, private exponent, CRT // info. // We have everything needed from the publicKey (an RSA object) - // and privateKey (a PivRsaPrivateKey object) except for the + // and privateKey (an RSAPrivateKey object) except for the // private exponent. If you have the CRT info, you don't need the - // private exponent, so the PivRsaPrivateKey class doesn't keep + // private exponent, so the RSAPrivateKey class doesn't keep // it (and the YubiKey itself does not keep it). // But in order to build the RSA private key-containing object we // need to obtain the private exponent. Except we don't really. @@ -333,6 +336,7 @@ private static bool IsMatchingKeyAndCertRsa(PivRsaPrivateKey privateKey, RSA pub // using an arbitrary private exponent. RSAParameters publicParams = publicKey.ExportParameters(false); + RSAParameters keyParams = privateKey.Parameters; byte[] fakeExponent = new byte[publicParams.Modulus.Length]; byte[] modCopy = new byte[publicParams.Modulus.Length]; byte[] expCopy = new byte[publicParams.Exponent.Length]; @@ -358,11 +362,11 @@ private static bool IsMatchingKeyAndCertRsa(PivRsaPrivateKey privateKey, RSA pub try { rsaParams.D = fakeExponent; - rsaParams.DP = privateKey.ExponentP.ToArray(); - rsaParams.DQ = privateKey.ExponentQ.ToArray(); - rsaParams.InverseQ = privateKey.Coefficient.ToArray(); - rsaParams.P = privateKey.PrimeP.ToArray(); - rsaParams.Q = privateKey.PrimeQ.ToArray(); + rsaParams.DP = keyParams.DP; + rsaParams.DQ = keyParams.DQ; + rsaParams.InverseQ = keyParams.InverseQ; + rsaParams.P = keyParams.P; + rsaParams.Q = keyParams.Q; rsaParams.Modulus = modCopy; rsaParams.Exponent = expCopy; @@ -385,11 +389,9 @@ private static bool IsMatchingKeyAndCertRsa(PivRsaPrivateKey privateKey, RSA pub } } -private static bool IsMatchingKeyAndCertEcc(PivEccPrivateKey privateKey, byte[] publicKey) +private static bool IsMatchingKeyAndCertEcc(ECPrivateKey privateKey, byte[] publicKey) { - bool returnValue = false; - - ECCurve eccCurve = privateKey.Algorithm == PivAlgorithm.EccP256 ? + ECCurve eccCurve = privateKey.KeyType == KeyType.ECP256 ? ECCurve.CreateFromValue("1.2.840.10045.3.1.7") : ECCurve.CreateFromValue("1.3.132.0.34"); @@ -407,7 +409,7 @@ private static bool IsMatchingKeyAndCertEcc(PivEccPrivateKey privateKey, byte[] Array.Copy(publicKey, 1 + coordLength, yCoord, 0, coordLength); eccParams.Q.X = xCoord; eccParams.Q.Y = yCoord; - eccParams.D = privateKey.PrivateValue.ToArray(); + eccParams.D = privateKey.Parameters.D; // To determine if the public key in the cert is the partner // to the private key, sign random data using that private diff --git a/docs/users-manual/application-piv/cert-request.md b/docs/users-manual/application-piv/cert-request.md index a9d858e6f..f23783347 100644 --- a/docs/users-manual/application-piv/cert-request.md +++ b/docs/users-manual/application-piv/cert-request.md @@ -89,20 +89,17 @@ see the .NET documentation. ### Public key -When you generate a key pair on the YubiKey, a `PivPublicKey` is returned. The +When you generate a key pair on the YubiKey, an `IPublicKey` is returned. The `CertificateRequest` class needs that public key as an instance of the `RSA` class. -The `PivSampleCode.KeyConverter` class demonstrates how to get an `RSA` object from a -`PivPublicKey`. Your code might look something like this. +The `PivSampleCode.KeyConverter` class demonstrates how to get an `RSA` object from an +`IPublicKey`. Your code might look something like this. ```csharp - PivRsaPublicKey rsaPublic = pivSession.GenerateKeyPair(...); + var rsaPublic = (RSAPublicKey)pivSession.GenerateKeyPair( + PivSlot.Authentication, KeyType.RSA2048); - var rsaParams = new RSAParameters(); - rsaParams.Modulus = rsaPublic.Modulus.ToArray(); - rsaParams.Exponent = rsaPublic.PublicExponent.ToArray(); - - RSA rsaPublicKeyObject = RSA.Create(rsaParams); + RSA rsaPublicKeyObject = RSA.Create(rsaPublic.Parameters); ``` An `RSA` object can contain a public key only or both public and private keys. Later on, diff --git a/docs/users-manual/application-piv/commands.md b/docs/users-manual/application-piv/commands.md index 5be19b787..454c2d2e1 100644 --- a/docs/users-manual/application-piv/commands.md +++ b/docs/users-manual/application-piv/commands.md @@ -75,8 +75,8 @@ To see the serial number as a decimal string, use `ToString()`. For example, ```C# int serialNumber = serialResponse.GetData(); - string decimalSerial = serialNumber.GetString(); - string hexSerial = serialNumber.GetString("X"); + string decimalSerial = serialNumber.ToString(); + string hexSerial = serialNumber.ToString("X"); // Print out the decimalSerial to get something like "11409355" // Print out the hexSerial to get something like "00AE17CB" diff --git a/docs/users-manual/application-piv/migrate-smartcardnet.md b/docs/users-manual/application-piv/migrate-smartcardnet.md index 621a05563..92faa62ad 100644 --- a/docs/users-manual/application-piv/migrate-smartcardnet.md +++ b/docs/users-manual/application-piv/migrate-smartcardnet.md @@ -282,6 +282,8 @@ In the SmartCard.NET API, here is how you load the MSROOTS data onto the YubiKey ```csharp // Note that there is a limit of 3058 bytes for the data. byte[] msRootsData = CollectMsRootsData(); + // Note: The old API uses string for PINs. The SDK uses byte[] and the + // KeyCollector pattern for secure PIN handling. string pin = CollectPin(); var memoryStream = new MemoryStream(msRootsData); diff --git a/docs/users-manual/application-security-domain/security-domain-keys.md b/docs/users-manual/application-security-domain/security-domain-keys.md index 9b8fc9fb6..7dcb7b3ac 100644 --- a/docs/users-manual/application-security-domain/security-domain-keys.md +++ b/docs/users-manual/application-security-domain/security-domain-keys.md @@ -84,11 +84,11 @@ var publicKey = session.GenerateEcKey(keyRef); ```csharp // Import existing private key -var privateKey = new ECPrivateKeyParameters(ecdsa); +var privateKey = ECPrivateKey.CreateFromParameters(ecdsa.ExportParameters(true)); session.PutKey(keyRef, privateKey); // Import public key -var publicKey = new ECPublicKeyParameters(ecdsaPublic); +var publicKey = ECPublicKey.CreateFromParameters(ecdsaPublic.ExportParameters(false)); session.PutKey(keyRef, publicKey); ``` diff --git a/docs/users-manual/application-u2f/fips-mode.md b/docs/users-manual/application-u2f/fips-mode.md index 10a0db939..62551e40d 100644 --- a/docs/users-manual/application-u2f/fips-mode.md +++ b/docs/users-manual/application-u2f/fips-mode.md @@ -42,15 +42,15 @@ version 5 FIPS series YubiKeys. Even though it is a FIPS-certified device, its F application is not FIPS-compliant. Note that a version 5 FIPS series YubiKey supports FIDO2 and that can be FIPS-compliant. -You can determine programmatically whether a given YubiKey is a 4 FIPS Series key with the -[GetDeviceInfoCommand](u2f-commands.md#get-device-info). +You can determine programmatically whether a given YubiKey is a 4 FIPS Series key using +the device info available through the `IYubiKeyDevice` interface (see +[Get device info](u2f-commands.md#get-device-info) for protocol details). ```c# - var getDeviceInfoCmd = new GetDeviceInfoCommand(); - GetDeviceInfoResponse getDeviceInfoRsp = connection.SendCommand(getDeviceInfoCmd); - YubiKeyDeviceInfo deviceInfo = getDeviceInfoRsp.GetData(); + IYubiKeyDevice yubiKeyDevice = YubiKeyDevice.FindAll().FirstOrDefault() + ?? throw new InvalidOperationException("No YubiKey device found."); - if (deviceInfo.IsFipsSeries && (deviceInfo.FirmwareVersion.Major == 4)) + if (yubiKeyDevice.IsFipsSeries && (yubiKeyDevice.FirmwareVersion.Major == 4)) { // This is a version 4 FIPS YubiKey. } @@ -69,17 +69,17 @@ programmatically determine if a YubiKey is in FIPS mode or not with [VerifyFipsModeCommand](u2f-commands.md#verify-fips-mode). ```c# - var getDeviceInfoCmd = new GetDeviceInfoCommand(); - GetDeviceInfoResponse getDeviceInfoRsp = connection.SendCommand(getDeviceInfoCmd); - YubiKeyDeviceInfo deviceInfo = getDeviceInfoRsp.GetData(); + IYubiKeyDevice yubiKeyDevice = YubiKeyDevice.FindAll().FirstOrDefault() + ?? throw new InvalidOperationException("No YubiKey device found."); - // Is this YubiKey 4 FIPS series? - if (deviceInfo.IsFipsSeries && (deviceInfo.FirmwareVersion.Major == 4)) + // Is this YubiKey 4 FIPS series? + if (yubiKeyDevice.IsFipsSeries && (yubiKeyDevice.FirmwareVersion.Major == 4)) { // If it is YubiKey 4 FIPS series, we can get the FIPS mode. + using IYubiKeyConnection connection = yubiKeyDevice.Connect(YubiKeyApplication.FidoU2f); var vfyFipsModeCmd = new VerifyFipsModeCommand(); VerifyFipsModeResponse vfyFipsModeRsp = connection.SendCommand(vfyFipsModeCmd); - if (vfyFipsMode.GetData()) + if (vfyFipsModeRsp.GetData()) { // If the return from GetData is true, then this is // YubiKey 4 FIPS series in FIPS mode. @@ -88,7 +88,7 @@ programmatically determine if a YubiKey is in FIPS mode or not with } // Note that if the YubiKey is not version 4 FIPS series, the // VerifyFipsModeCommand is undefined. A call to VerifyFipsModeResponse.GetData - // will result in an exception. + // will result in an exception. } ``` diff --git a/docs/users-manual/getting-started/overview-of-sdk.md b/docs/users-manual/getting-started/overview-of-sdk.md index 888f040c0..58a8c6a99 100644 --- a/docs/users-manual/getting-started/overview-of-sdk.md +++ b/docs/users-manual/getting-started/overview-of-sdk.md @@ -209,7 +209,7 @@ public static class Program // Generate a public-private keypair var publicKey = piv.GenerateKeyPair( PivSlot.CardAuthentication, - PivAlgorithm.Rsa2048); + KeyType.RSA2048); } } } diff --git a/docs/users-manual/sdk-programming-guide/key-collector.md b/docs/users-manual/sdk-programming-guide/key-collector.md index 67aac5cdd..105319213 100644 --- a/docs/users-manual/sdk-programming-guide/key-collector.md +++ b/docs/users-manual/sdk-programming-guide/key-collector.md @@ -246,12 +246,12 @@ For example, here is a possibility. try { int pinLength = CollectPin(pinData); - while (!pivSession.TryVerifyPin(pinData.Slice(0, pinLength, out int? retriesRemaining)) + while (!pivSession.TryVerifyPin(pinData.Slice(0, pinLength), out int? retriesRemaining)) { - pinLength = CollectPin(someMessage, retriesRemaining, pinData)) + pinLength = CollectPin(someMessage, retriesRemaining, pinData); if (pinLength == 0) { - throw OperationCanceledException(message); + throw new OperationCanceledException(message); } } } @@ -465,9 +465,14 @@ using Yubico.YubiKey; public class MyKeyCollector { - private byte[] _currentValue = new byte[MaxValueLength] + private byte[] _currentValue = new byte[MaxValueLength]; private int _currentLength; - public Memory CurrentValue = new Memory(_currentValue); + public Memory CurrentValue; + + public MyKeyCollector() + { + CurrentValue = new Memory(_currentValue); + } public bool SampleKeyCollectorDelegate(KeyEntryData keyEntryData) { @@ -479,7 +484,7 @@ using Yubico.YubiKey; switch (keyEntryData.Request) { case KeyEntryRequest.Release: - CryptographicOperations.ZeroMemory(CurrentValue.Span) + CryptographicOperations.ZeroMemory(CurrentValue.Span); break; case KeyEntryRequest.VerifyPivPin: diff --git a/docs/users-manual/sdk-programming-guide/secure-channel-protocol.md b/docs/users-manual/sdk-programming-guide/secure-channel-protocol.md index 936e49ea2..8e9b0eb6d 100644 --- a/docs/users-manual/sdk-programming-guide/secure-channel-protocol.md +++ b/docs/users-manual/sdk-programming-guide/secure-channel-protocol.md @@ -97,17 +97,17 @@ var keyReference = KeyReference.Create(keyId, keyVersionNumber); var certificates = sdSession.GetCertificates(keyReference); // Verify the Yubikey's certificate chain against a trusted root using your implementation -CertificateChainVerifier.Verify(certificateList) +CertificateChainVerifier.Verify(certificates); -// Use the verified leaf certificate to construct ECPublicKeyParameters -var publicKey = certificates.Last().GetECDsaPublicKey(); -var scp11Params = new Scp11KeyParameters(keyReference, new ECPublicKeyParameters(publicKey)); +// Use the verified leaf certificate to construct an ECPublicKey +var ecDsa = certificates.Last().GetECDsaPublicKey()!; +var scp11Params = new Scp11KeyParameters(keyReference, ECPublicKey.CreateFromParameters(ecDsa.ExportParameters(false))); // Use SCP11b parameters to open connection using (var pivSession = new PivSession(yubiKeyDevice, scp11Params)) { // All PivSession-commands are now automatically protected by SCP11 - session.GenerateKeyPair(PivSlot.Retired12, PivAlgorithm.EccP256, PivPinPolicy.Always); // Protected by SCP11 + pivSession.GenerateKeyPair(PivSlot.Retired12, KeyType.ECP256, PivPinPolicy.Always); // Protected by SCP11 } ``` @@ -119,7 +119,7 @@ using (var pivSession = new PivSession(yubiKeyDevice, scp11Params)) // Using SCP03 StaticKeys scp03Keys = RetrieveScp03KeySet(); // Your static keys using Scp03KeyParameters scp03Params = Scp03KeyParameters.FromStaticKeys(scp03Keys); -using (var pivSession = new PivSession(yubiKeyDevice, scp03params)) +using (var pivSession = new PivSession(yubiKeyDevice, scp03Params)) { // All PivSession-commands are now automatically protected by SCP03 } @@ -137,8 +137,8 @@ using (var pivSession = new PivSession(yubiKeyDevice, scp11Params)) // Using SCP03 StaticKeys scp03Keys = RetrieveScp03KeySet(); // Your static keys -using Scp03KeyParamaters scp03Params = Scp03KeyParameters.FromStaticKeys(scp03Keys); -using (var oathSession = new OathSession(yubiKeyDevice, scp03params)) +using Scp03KeyParameters scp03Params = Scp03KeyParameters.FromStaticKeys(scp03Keys); +using (var oathSession = new OathSession(yubiKeyDevice, scp03Params)) { // All oathSession-commands are now automatically protected by SCP03 } @@ -156,8 +156,8 @@ using (var oathSession = new OathSession(yubiKeyDevice, scp11Params)) // Using SCP03 StaticKeys scp03Keys = RetrieveScp03KeySet(); // Your static keys -using Scp03KeyParamaters scp03Params = Scp03KeyParameters.FromStaticKeys(scp03Keys); -using (var otpSession = new OtpSession(yubiKeyDevice, scp03params)) +using Scp03KeyParameters scp03Params = Scp03KeyParameters.FromStaticKeys(scp03Keys); +using (var otpSession = new OtpSession(yubiKeyDevice, scp03Params)) { // All otpSession-commands are now automatically protected by SCP03 } @@ -174,15 +174,15 @@ using (var otpSession = new OtpSession(yubiKeyDevice, scp11Params)) ```csharp // Using SCP03 StaticKeys scp03Keys = RetrieveScp03KeySet(); // Your static keys -using Scp03KeyParamaters scp03Params = Scp03KeyParameters.FromStaticKeys(scp03Keys); -using (var yubiHsmSession = new YubiHsmAuthSession(yubiKeyDevice, scp03params)) +using Scp03KeyParameters scp03Params = Scp03KeyParameters.FromStaticKeys(scp03Keys); +using (var yubiHsmSession = new YubiHsmAuthSession(yubiKeyDevice, scp03Params)) { // All YubiHsmSession-commands are now automatically protected by SCP03 } // Using SCP11b var keyReference = KeyReference.Create(ScpKeyIds.Scp11B, kvn); -using (var yubiHsmSession = new YubiHsmSession(yubiKeyDevice, scp11Params)) +using (var yubiHsmSession = new YubiHsmAuthSession(yubiKeyDevice, scp11Params)) { // All yubiHsmSession-commands are now automatically protected by SCP11 } @@ -420,9 +420,10 @@ Unlike SCP03's static keys, SCP11 uses `Scp11KeyParameters` which can contain: ```csharp // SCP11b basic parameters var keyReference = KeyReference.Create(ScpKeyIds.Scp11B, 0x1); +ECParameters ecParams = ecdsa.ExportParameters(includePrivateParameters: false); var scp11Params = new Scp11KeyParameters( keyReference, - new ECPublicKeyParameters(publicKey)); + ECPublicKey.CreateFromParameters(ecParams)); // SCP11a/c with full certificate chain var scp11Params = new Scp11KeyParameters( @@ -442,10 +443,10 @@ using var session = new SecurityDomainSession(yubiKeyDevice, Scp03KeyParameters. // Generate new EC key pair var keyReference = KeyReference.Create(ScpKeyIds.Scp11B, 0x3); -var publicKey = session.GenerateEcKey(keyReference); +var publicKey = session.GenerateEcKey(keyReference, 0); // Import existing key pair -var privateKey = new ECPrivateKeyParameters(ecdsa); +var privateKey = ECPrivateKey.CreateFromParameters(ecdsa.ExportParameters(true)); session.PutKey(keyReference, privateKey); // Store certificates @@ -480,7 +481,7 @@ var leaf = certificateList.Last(); var ecDsaPublicKey = leaf.PublicKey.GetECDsaPublicKey()!.ExportParameters(false); var keyParams = new Scp11KeyParameters( keyReference, - new ECPublicKeyParameters(ecDsaPublicKey)); + ECPublicKey.CreateFromParameters(ecDsaPublicKey)); // Use with any application using var pivSession = new PivSession(yubiKeyDevice, keyParams); @@ -502,7 +503,8 @@ var newPublicKey = session.GenerateEcKey(keyRef); // Setup off-card entity (OCE) var oceRef = KeyReference.Create(OceKid, kvn); -var ocePublicKey = new ECPublicKeyParameters(oceCerts.Ca.PublicKey.GetECDsaPublicKey()); +var oceEcDsa = oceCerts.Ca.PublicKey.GetECDsaPublicKey()!; +var ocePublicKey = ECPublicKey.CreateFromParameters(oceEcDsa.ExportParameters(false)); session.PutKey(oceRef, ocePublicKey); // Store CA identifier @@ -510,11 +512,12 @@ var ski = GetSubjectKeyIdentifier(oceCerts.Ca); session.StoreCaIssuer(oceRef, ski); // Create SCP11a parameters +// privateKey is the OCE private key as ECDsa var scp11Params = new Scp11KeyParameters( keyRef, - new ECPublicKeyParameters(newPublicKey.Parameters), + newPublicKey, oceRef, - new ECPrivateKeyParameters(privateKey), + ECPrivateKey.CreateFromParameters(privateKey.ExportParameters(true)), certChain); // Use the secure connection