PKCS11 unwrap private RSA key to eToken HSM - pkcs#11

I am trying to transfer an RSA private key to my HSM (SafeNet eToken) via PKCS#11 interop, and and then unwrap it on the HSM.
This is my code (updated):
session.Login(CKU.CKU_USER, pin);
var x509Certificate = new X509Certificate2(File.ReadAllBytes(path), "", X509KeyStorageFlags.Exportable);
var privateKey = x509Certificate.PrivateKey as RSACryptoServiceProvider;
var keyPair = DotNetUtilities.GetRsaKeyPair(privateKey);
byte[] privateKeyBytes;
using (var memoryStream = new MemoryStream())
{
using (TextWriter streamWriter = new StreamWriter(memoryStream))
{
var pemWriter = new PemWriter(streamWriter);
pemWriter.WriteObject(keyPair.Private);
streamWriter.Flush();
}
privateKeyBytes = memoryStream.GetBuffer();
}
// Create temporary DES3 key for wrapping/unwrapping
var tempKeyAttributes = new List<ObjectAttribute>
{
new ObjectAttribute(CKA.CKA_CLASS, CKO.CKO_SECRET_KEY),
new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_DES3),
new ObjectAttribute(CKA.CKA_ENCRYPT, true),
new ObjectAttribute(CKA.CKA_UNWRAP, true)
};
var tempKey = session.GenerateKey(new Mechanism(CKM.CKM_DES3_KEY_GEN), tempKeyAttributes);
var encrypted =
session.Encrypt(new Mechanism(CKM.CKM_DES3_ECB), tempKey, privateKeyBytes);
string label = "private1";
// Define how the new RSA private key should look like on the HSM
var privateKeyAttributes = new List<ObjectAttribute>
{
new ObjectAttribute(CKA.CKA_CLASS, CKO.CKO_PRIVATE_KEY),
new ObjectAttribute(CKA.CKA_TOKEN, true),
new ObjectAttribute(CKA.CKA_PRIVATE, true),
new ObjectAttribute(CKA.CKA_MODIFIABLE, true),
new ObjectAttribute(CKA.CKA_SENSITIVE, false),
new ObjectAttribute(CKA.CKA_LABEL, label),
new ObjectAttribute(CKA.CKA_ID, Encoding.ASCII.GetBytes(label)),
new ObjectAttribute(CKA.CKA_ALWAYS_AUTHENTICATE, false),
new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_RSA),
};
var privateKeyHandle = session.UnwrapKey(new Mechanism(CKM.CKM_DES3_ECB), tempKey,
encrypted, privateKeyAttributes);
//results in: Method C_UnwrapKey returned CKR_WRAPPED_KEY_INVALID
But it does not work - fails with Net.Pkcs11Interop.Common.Pkcs11Exception: Method C_UnwrapKey returned CKR_TEMPLATE_INCONSISTENT.
(UPDATED)
Now it results in CKR_WRAPPED_KEY_INVALID.
But if I import the same PFX file manuall using SafeNet, no errors occur - everything seems fine.
Any ideas? Maybe there are some parameters I used wrong?

FINALLY the code that does the thing:
var x509Certificate = new X509Certificate2(File.ReadAllBytes(path), "",
X509KeyStorageFlags.Exportable);
var privateKey = x509Certificate.PrivateKey as RSACryptoServiceProvider;
if (privateKey == null) throw new Exception($"Private key is null for {x509Certificate.SerialNumber}");
var privateKeyParams = privateKey.ExportParameters(true);
session.Login(CKU.CKU_USER, pin);
// Create temporary DES3 key for wrapping/unwrapping
var tempKeyAttributes = new List<ObjectAttribute>
{
new ObjectAttribute(CKA.CKA_CLASS, CKO.CKO_SECRET_KEY),
new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_DES3),
new ObjectAttribute(CKA.CKA_ENCRYPT, true),
new ObjectAttribute(CKA.CKA_DECRYPT, true),
new ObjectAttribute(CKA.CKA_UNWRAP, true),
new ObjectAttribute(CKA.CKA_WRAP, true)
};
// Preparing unencrypted private key
var unencryptedPrivateKey = PrivateKeyInfoFactory.CreatePrivateKeyInfo(
new RsaPrivateCrtKeyParameters(
new BigInteger(1, privateKeyParams.Modulus),
new BigInteger(1, privateKeyParams.Exponent),
new BigInteger(1, privateKeyParams.D),
new BigInteger(1, privateKeyParams.P),
new BigInteger(1, privateKeyParams.Q),
new BigInteger(1, privateKeyParams.DP),
new BigInteger(1, privateKeyParams.DQ),
new BigInteger(1, privateKeyParams.InverseQ))).GetEncoded();
var tempKey = session.GenerateKey(new Mechanism(CKM.CKM_DES3_KEY_GEN), tempKeyAttributes);
var result = new MemoryStream();
var stream = new MemoryStream(unencryptedPrivateKey);
//Encrypting
session.Encrypt(new Mechanism(CKM.CKM_DES3_ECB), tempKey, stream,
result);
var encrypted = result.ToArray();
string label = x509Certificate.SerialNumber;
// Define how the new RSA private key should look like on the HSM
var privateKeyAttributes = new List<ObjectAttribute>
{
new ObjectAttribute(CKA.CKA_CLASS, CKO.CKO_PRIVATE_KEY),
new ObjectAttribute(CKA.CKA_TOKEN, true),
new ObjectAttribute(CKA.CKA_PRIVATE, true),
new ObjectAttribute(CKA.CKA_MODIFIABLE, true),
new ObjectAttribute(CKA.CKA_SENSITIVE, false),
new ObjectAttribute(CKA.CKA_LABEL, label),
new ObjectAttribute(CKA.CKA_ID, Encoding.ASCII.GetBytes(label)),
new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_RSA)
};
var privateKeyHandle = session.UnwrapKey(new Mechanism(CKM.CKM_DES3_ECB), tempKey,
encrypted, privateKeyAttributes);
return privateKeyHandle;

Related

JwtBearer middleware with ES256 always 401 Bearer error="invalid_token", error_description="The signature key was not found"

token is created using
public class AppTokenHandler : TokenValidator, IAppTokenHandler
{
private readonly JwtSecurityTokenHandler _handler = new JwtSecurityTokenHandler();
private readonly AppTokenConfiguration _appTokenConfiguration;
private readonly RsaSecurityKey _publicKey;
private readonly ECDsa _key;
public AppTokenHandler(IOptions<AppTokenConfiguration> appTokenConfiguration, RsaSecurityKey publicKey, ECDsa key)
{
_appTokenConfiguration = appTokenConfiguration.Value;
_publicKey = publicKey;
_key = key;
}
public string Create(Dictionary<string, object> claims)
{
var name = claims["name"].ToString();
////create token security key used to sign token from app's rsa private key
//using var rsa = RSA.Create();
//var rsaKey = _appTokenConfiguration.RsaKey;
//rsa.ImportRSAPrivateKey(Convert.FromBase64String(rsaKey), out _);
//RsaSecurityKey rsaSecurityKey = new(rsa);
////create signing credentials, specifying not to cache signature provider
//SigningCredentials signingCredentials = new(rsaSecurityKey, SecurityAlgorithms.RsaSha256)
//{
// CryptoProviderFactory = new CryptoProviderFactory { CacheSignatureProviders = false }
//};
SigningCredentials signingCredentials = new(new ECDsaSecurityKey(_key), SecurityAlgorithms.EcdsaSha256);
// create token
var tokenDescriptor = new SecurityTokenDescriptor
{
Audience = _appTokenConfiguration.Audience,
Claims = claims,
Expires = DateTime.UtcNow.AddDays(2),
IssuedAt = DateTime.UtcNow,
Issuer = _appTokenConfiguration.Issuer,
SigningCredentials = signingCredentials,
Subject = new ClaimsIdentity(new Claim[]
{
new Claim(ClaimTypes.NameIdentifier, name),
})
};
var encodedJwt = _handler.CreateEncodedJwt(tokenDescriptor);
return encodedJwt;
}
public override bool Validate(string tokenString, out JwtSecurityToken token, out SecurityTokenValidationException validationException)
{
validationException = null;
token = null;
var publicKey = ECDsa.Create(_key.ExportParameters(false));
var validationParameters = new TokenValidationParameters
{
// validate lifetime
RequireExpirationTime = true,
ValidateLifetime = true,
// validate audience
RequireAudience = true,
ValidateAudience = true,
ValidAudience = _appTokenConfiguration.Audience,
// validate issuer
ValidateIssuer = true,
ValidIssuer = _appTokenConfiguration.Issuer,
// set source of name
NameClaimType = "name",
// validate signing key
RequireSignedTokens = true,
ValidateIssuerSigningKey = true,
//IssuerSigningKey = _publicKey
IssuerSigningKey = new ECDsaSecurityKey(publicKey)
};
try
{
var validate = _handler.ValidateToken(tokenString, validationParameters, out var validatedSecurityToken);
token = _handler.ReadJwtToken(tokenString);
}
catch (SecurityTokenValidationException ex)
{
validationException = ex;
return false;
}
catch
{
throw;
}
return true;
}
public Dictionary<string, object> MapClaims(JwtSecurityToken accessToken, JwtSecurityToken idToken)
{
List<string> claimKeys = new()
{
"name",
"preferred_username",
"oid",
"tid",
"azp",
"family_name",
"given_name",
"email"
};
var claims = accessToken?
.Claims
.Where(x=>claimKeys.Contains(x.Type))
.ToDictionary(x => x.Type, x => x.Value as object)
??
new Dictionary<string, object>();
var idTokenClaims = idToken
.Claims
.Where(x => claimKeys.Contains(x.Type))
.ToDictionary(x => x.Type, x => x.Value as object);
foreach (var claim in idTokenClaims.Where(x => !claims.ContainsKey(x.Key)))
claims.Add(claim.Key, claim.Value);
claims.Add("scp", "app_authorized_user");
return claims;
}
}
token is configured using
public class AppTokenOptions
{
public static Action<JwtBearerOptions> ConfigureToken(IServiceCollection services)
{
return options =>
{
var serviceProvider = services.BuildServiceProvider();
var authConfig = serviceProvider.GetRequiredService<IOptions<AppTokenConfiguration>>();
var publicKey = serviceProvider.GetRequiredService<RsaSecurityKey>();
var privkey = serviceProvider.GetRequiredService<ECDsa>();
//var key = ECDsa.Create(privkey.ExportParameters(false));
options.IncludeErrorDetails = true;
options.TokenValidationParameters = new TokenValidationParameters
{
// validate lifetime
RequireExpirationTime = true,
ValidateLifetime = true,
// validate audience
RequireAudience = true,
ValidateAudience = true,
ValidAudience = authConfig.Value.Audience,
// validate issuer
ValidateIssuer = true,
ValidIssuer = authConfig.Value.Issuer,
// set source of name
NameClaimType = "name",
// validate signing key
RequireSignedTokens = true,
ValidateIssuerSigningKey = true,
//IssuerSigningKey = publicKey
IssuerSigningKey = new ECDsaSecurityKey(ECDsa.Create(privkey.ExportParameters(false)))
};
options.Events = new JwtBearerEvents();
options.Events.OnTokenValidated = async context =>
{
(context.Principal?.Identity as ClaimsIdentity)?.AddClaim(new Claim("cpcb", "test"));
};
};
}
}
auth is added immediately in ConfigureServices of Startup.cs using
public static class AuthServicesRegistration
{
public static IServiceCollection ConfigureApplicationAuthServices(this IServiceCollection services, IConfiguration Configuration)
{
// get relevant config sections
IConfiguration appAuth= Configuration.GetSection("Auth:app");
IConfiguration aadIdTokenAuth = Configuration.GetSection("Auth:AADIdToken");
// create keys for app token
using (RSA rsa = RSA.Create(3072))
{
string rsaKey = Convert.ToBase64String(rsa.ExportRSAPrivateKey());
string rsaPublicKey = Convert.ToBase64String(rsa.ExportRSAPublicKey());
appAuth["RsaKey"] = rsaKey;
appAuth["RsaPublicKey"] = rsaPublicKey;
}
// bind auth configs
services.Configure<AppTokenConfiguration>(appAuth);
services.Configure<AzureAdIdTokenConfiguration>(aadIdTokenAuth);
// add public key instance as singleton
// so it can be used in .net's token validation middleware
// otherwise if just declared when defined token validation parameters
// the RSA instance will be prematurely disposed and you will get misleading 401s
services.AddSingleton(provider => {
RSA rsa = RSA.Create();
rsa.ImportRSAPublicKey(Convert.FromBase64String(appAuth["RsaPublicKey"]), out _);
return new RsaSecurityKey(rsa);
});
services.AddSingleton(provider =>
{
return ECDsa.Create(ECCurve.NamedCurves.nistP256);
});
// add provider for microsoft openidconnect config
services.AddSingleton<IOpenIdConnectConfigurationProvider>(provider =>
{
var stsDiscoveryEndpoint = "https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration";
var configProvider = new OpenIdConnectConfigurationProvider(stsDiscoveryEndpoint, new OpenIdConnectConfigurationRetriever());
configProvider.AutomaticRefreshInterval = TimeSpan.FromHours(1);
return configProvider;
});
// add authentication schemes
// default is app token
services.AddAuthentication("app")
.AddJwtBearer("app", AppTokenOptions.ConfigureToken(services))
.AddMicrosoftIdentityWebApi(Configuration, "Auth:AzureAd", "aad");
// configure aad token options
services.Configure("aad", AzureAdTokenOptions.ConfigureAadToken());
// add authorization
services.AddAuthorization();
// add auth related services
services.AddScoped<IAppTokenHandler, AppTokenHandler>();
services.AddScoped<ITokenValidator, MicrosoftIdTokenValidator>();
return services;
}
}
token generation endpoint and test endpoint to validate token
[ApiController]
[Route("api/auth")]
public class AuthController : ControllerBase
{
private readonly IAppTokenHandler _appTokenHandler;
private readonly ITokenValidator _idTokenValidator;
public AuthController(IAppTokenHandler tokenHandler, ITokenValidator idTokenValidator) : base()
{
_appTokenHandler = tokenHandler;
_idTokenValidator = idTokenValidator;
}
/// <summary>
/// Returns token for requested resource verifying using msal accesstoken
/// </summary>
/// <returns></returns>
[Authorize(AuthenticationSchemes = "aad")]
[RequiredScope(AcceptedScope = new[] { "app_login" })]
[Route("token")]
[HttpGet]
public async Task<IActionResult> token()
{
if (!Request.Headers.TryGetValue("identity", out var idTokenString)) return Unauthorized("No identity present to verify");
var aadToken = await HttpContext.GetTokenAsync("aad", "access_token");
JwtSecurityToken accessToken = null;
if (aadToken != null)
{
accessToken = new JwtSecurityToken(aadToken);
}
// verify idToken
if (!_idTokenValidator.Validate(idTokenString, out var idToken, out var validationException))
{
return Unauthorized($"invalid id token: {validationException.Message}");
}
// get / verify user
// get claims from tokens
var claims = _appTokenHandler.MapClaims(accessToken, idToken);
// generate token
var encodedJwt = _appTokenHandler.Create(claims);
return Ok(encodedJwt);
}
/// <summary>
/// Test authorize endpoint
/// </summary>
/// <returns></returns>
[Authorize]
[RequiredScope(AcceptedScope = new[] { "app_authorized_user" })]
[Route("validate/{token}")]
[HttpGet]
public async Task<IActionResult> validate(string token)
{
var authorization = Request.Headers.Authorization.ToString().Substring("Bearer ".Length).Trim();
try
{ // both validate calls are successful when authorize attribute is commented out
if (_appTokenHandler.Validate(token, out _, out var ex))
{
Debug.WriteLine("valid token");
}
else
{
Debug.WriteLine("invalid token", ex.Message);
}
if (_appTokenHandler.Validate(authorization, out _, out var ex2))
{
Debug.WriteLine("valid auth header");
}
else
{
Debug.WriteLine("invalid auth header", ex2.Message);
}
}
catch (Exception exc)
{
Debug.WriteLine(exc.Message);
}
return Ok(token);
}
}
if i swap out ES256 for RSA I had previously wired up, no issues. However, when I tried swapping out RSA for ES256, I got the error "The signature key was not found". If I remove the authorize attribute on the validate endpoint, get a token from the token endpoint and then verify the token using the app token handler, it's valid. There seems to be an issue with the jwt bearer middleware?? I have tried using the full ECDsa instead of just the public key, a singleton of an ECDsaSecurityKey with a key id and without a key id, a singleton of a jsonwebkey, and now a singleton of just the ecdsa. All same result. app token handler instance validates it with same token validation parameters, but jwt bearer middleware fails authorization. And again, if I swap out the signing credentials to use the RSA credentials, everything works just fine.
Am I creating the signing keys incorrectly?
Am I providing the public / private keys incorrectly to jwt bearer middleware?
Am I missing something in token creation?
How do I hook into jwt bearer middleware to get a better idea of what is going on? I see there is the ontokenvalidated event but that is not being hit obviously, is there an event I can hook into that might provide more info into what is going wrong?
Thanks!
I think the ecdsa instance used to create private key was getting displosed too early (?)
Ended up creating the ecdsa and saving the ecparams to config (similar as with rsa keys), created singleton of ecdsasecuritykey with just q and curve (so just public key), used serviceprovider to get ecdsasecuritykey to set as issuersigningkey for token validation in configure jwtbeareroptions, then used all ecparams from config (bound in apptokenconfiguration class) to create private key ecdsasecuritykey when creating the token
in configureapplicationauthservices
// create keys for app tokens
using (RSA rsa = RSA.Create(3072))
using (ECDsa ecdsa = ECDsa.Create(ECCurve.NamedCurves.nistP256))
{
// rsa
string rsaKey = Convert.ToBase64String(rsa.ExportRSAPrivateKey());
string rsaPublicKey = Convert.ToBase64String(rsa.ExportRSAPublicKey());
appAuth["RsaKey"] = rsaKey;
appAuth["RsaPublicKey"] = rsaPublicKey;
appAuth["RsaKid"] = Guid.NewGuid().ToString();
// ecdsa
ECParameters ecParams = ecdsa.ExportParameters(true);
appAuth["D"] = Convert.ToBase64String(ecParams.D);
appAuth["QX"] = Convert.ToBase64String(ecParams.Q.X);
appAuth["QY"] = Convert.ToBase64String(ecParams.Q.Y);
appAuth["EcKid"] = Guid.NewGuid().ToString();
}
// bind auth configs
services.Configure<AppTokenConfiguration>(appAuth);
services.Configure<AzureAdIdTokenConfiguration>(aadIdTokenAuth);
// add rsa public key instance as singleton
// so it can be used in .net's token validation middleware
// otherwise if just declared when defined token validation parameters
// the RSA instance will be prematurely disposed and you will get misleading 401s
services.AddSingleton(provider => {
RSA rsa = RSA.Create();
rsa.ImportRSAPublicKey(Convert.FromBase64String(appAuth["RsaPublicKey"]), out _);
return new RsaSecurityKey(rsa);
});
// add ecdsa public key same way as rsa
services.AddSingleton(provider =>
{
ECParameters ecParams = new ECParameters();
ecParams.Curve = ECCurve.NamedCurves.nistP256;
ecParams.Q = new ECPoint()
{
X = Convert.FromBase64String(appAuth["QX"]),
Y = Convert.FromBase64String(appAuth["QY"])
};
ECDsa ecdsa = ECDsa.Create(ecParams);
return new ECDsaSecurityKey(ecdsa);
});
token configuration for middleware
public static Action<JwtBearerOptions> ConfigureToken(IServiceCollection services)
{
return options =>
{
var serviceProvider = services.BuildServiceProvider();
var authConfig = serviceProvider.GetRequiredService<IOptions<AppTokenConfiguration>>();
var publicKey = serviceProvider.GetRequiredService<RsaSecurityKey>();
var ecpublicKey = serviceProvider.GetRequiredService<ECDsaSecurityKey>();
options.IncludeErrorDetails = true;
options.TokenValidationParameters = new TokenValidationParameters
{
// validate lifetime
RequireExpirationTime = true,
ValidateLifetime = true,
// validate audience
RequireAudience = true,
ValidateAudience = true,
ValidAudience = authConfig.Value.Audience,
// validate issuer
ValidateIssuer = true,
ValidIssuer = authConfig.Value.Issuer,
// set source of name
NameClaimType = "name",
// validate signing key
RequireSignedTokens = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = ecpublicKey
//IssuerSigningKey = publicKey
};
options.Events = new JwtBearerEvents();
options.Events.OnTokenValidated = async context =>
{
(context.Principal?.Identity as ClaimsIdentity)?.AddClaim(new Claim("cpcb", "test"));
};
options.Validate();
};
}
token creation (and validation for manual testing)
public class AppTokenHandler : TokenValidator, IAppTokenHandler
{
//private readonly JsonWebTokenHandler _handler = new();
private readonly JwtSecurityTokenHandler _handler = new();
private readonly AppTokenConfiguration _appTokenConfiguration;
private readonly RsaSecurityKey _publicKey;
private readonly ECDsaSecurityKey _ecdsaPublicKey;
public AppTokenHandler(IOptions<AppTokenConfiguration> appTokenConfiguration, RsaSecurityKey publicKey, ECDsaSecurityKey ecdsaPublicKey)
{
_appTokenConfiguration = appTokenConfiguration.Value;
_publicKey = publicKey;
_ecdsaPublicKey = ecdsaPublicKey;
}
public string Create(Dictionary<string, object> claims)
{
var name = claims["name"].ToString();
//create token security key used to sign token from app's rsa private key
//using var rsa = RSA.Create();
//var rsaKey = _appTokenConfiguration.RsaKey;
//rsa.ImportRSAPrivateKey(Convert.FromBase64String(rsaKey), out _);
//RsaSecurityKey rsaSecurityKey = new(rsa);
////create signing credentials, specifying not to cache signature provider
//SigningCredentials signingCredentials = new(rsaSecurityKey, SecurityAlgorithms.RsaSha256)
//{
// CryptoProviderFactory = new CryptoProviderFactory { CacheSignatureProviders = false }
//};
ECParameters ecParams = new ECParameters();
ecParams.Curve = ECCurve.NamedCurves.nistP256;
ecParams.D = Convert.FromBase64String(_appTokenConfiguration.D);
ecParams.Q = new ECPoint()
{
X = Convert.FromBase64String(_appTokenConfiguration.QX),
Y = Convert.FromBase64String(_appTokenConfiguration.QY)
};
using ECDsa ecdsa = ECDsa.Create(ecParams);
ECDsaSecurityKey ecdsaSecurityKey = new(ecdsa);
SigningCredentials signingCredentials = new(ecdsaSecurityKey, SecurityAlgorithms.EcdsaSha256)
{
CryptoProviderFactory = new CryptoProviderFactory { CacheSignatureProviders = false }
};
// create token
var tokenDescriptor = new SecurityTokenDescriptor
{
Audience = _appTokenConfiguration.Audience,
Claims = claims,
Expires = DateTime.UtcNow.AddDays(2),
IssuedAt = DateTime.UtcNow,
Issuer = _appTokenConfiguration.Issuer,
Subject = new ClaimsIdentity(new Claim[]
{
new Claim(ClaimTypes.NameIdentifier, name),
}),
SigningCredentials = signingCredentials
};
var encodedJwt = _handler.CreateEncodedJwt(tokenDescriptor);
return encodedJwt;
}
public override bool Validate(string tokenString, out JwtSecurityToken token, out SecurityTokenValidationException validationException)
{
validationException = null;
token = null;
var validationParameters = new TokenValidationParameters
{
// validate lifetime
RequireExpirationTime = true,
ValidateLifetime = true,
// validate audience
RequireAudience = true,
ValidateAudience = true,
ValidAudience = _appTokenConfiguration.Audience,
// validate issuer
ValidateIssuer = true,
ValidIssuer = _appTokenConfiguration.Issuer,
// set source of name
NameClaimType = "name",
// validate signing key
RequireSignedTokens = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = _ecdsaPublicKey
//IssuerSigningKey = _publicKey
};
try
{
var validate = _handler.ValidateToken(tokenString, validationParameters, out var validatedSecurityToken);
token = _handler.ReadJwtToken(tokenString);
}
catch (SecurityTokenValidationException ex)
{
validationException = ex;
return false;
}
catch
{
throw;
}
return true;
}
}
gonna clean this up a bit, but at least it is working correctly now :)

Any way to create a JWT token with key size 512? and changing default minimum size requirement of AsymmetricSignatureProvider

I am currently getting following error:
IDX10630: The 'Microsoft.IdentityModel.Tokens.RsaSecurityKey, KeyId: '...', InternalId: '5a946596-9fe6-4c91-8c52-9b140849c7a4'.' for signing cannot be smaller than '2048' bits. KeySize: '512'
I use the following method:
public string GetIdTokenString(Dictionary<string, string> inputClaims, string privateKey)
{
string result = null;
try
{
var tokenHandler = new JwtSecurityTokenHandler();
privateKey = privateKey.Replace("-----BEGIN ENCRYPTED PRIVATE KEY-----", String.Empty).Replace("-----END ENCRYPTED PRIVATE KEY-----", String.Empty);
var privateKeyBytes = Convert.FromBase64String(privateKey);
byte[] privateKeyPasswordBytes = Encoding.UTF8.GetBytes(mypassword);
List<Claim> claims = new List<Claim>();
foreach (var o in inputClaims)
{
claims.Add(new Claim(o.Key, o.Value));
}
int length = 0;
RSA rSA = RSA.Create();
rSA.ImportEncryptedPkcs8PrivateKey(privateKeyPasswordBytes, privateKeyBytes, out length);
RsaSecurityKey securitykey = new RsaSecurityKey(rSA)
{
KeyId = "......"
};
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(claims),
Expires = DateTime.UtcNow.AddSeconds(60 * 5),
Audience = ...,
Issuer = .....
};
tokenDescriptor.SigningCredentials = new SigningCredentials(securitykey, SecurityAlgorithms.RsaSha256Signature);
var token = tokenHandler.CreateToken(tokenDescriptor);
if (token != null && token is JwtSecurityToken)
{
result = (token as JwtSecurityToken).RawData;
}
}
catch (Exception ex)
{
Logger.Fatal(ex);
}
return result;
}
there is a code mentioned in post
Error Creating JWT Token using RSA Security Key with key size less than 2048
but I'm not able to run it in .net core 3.1
One more thing is about over riding value in
AsymmetricSignatureProvider.DefaultMinimumAsymmetricKeySizeInBitsForSigningMap
Any way i can change value of particular Key?
One thing i have tried which didn't work is
var mainclass = typeof(AsymmetricSignatureProvider)
.GetField(nameof(AsymmetricSignatureProvider.DefaultMinimumAsymmetricKeySizeInBitsForSigningMap), BindingFlags.Public | BindingFlags.Static );
var field = mainclass.GetValue(null) as Dictionary<string, int>;
if (field != null)
{
field["RS256"] = 512;
}
var mainclass2 = typeof(AsymmetricSignatureProvider).GetField(nameof(AsymmetricSignatureProvider.DefaultMinimumAsymmetricKeySizeInBitsForVerifyingMap), BindingFlags.Public | BindingFlags.Static);
var field2 = mainclass2.GetValue(null) as Dictionary<string, int>;
if (field2 != null)
{
field2["RS256"] = 512;
}
Following is the solution i have used
var mainclass = typeof(AsymmetricSignatureProvider)
.GetField(nameof(AsymmetricSignatureProvider.DefaultMinimumAsymmetricKeySizeInBitsForSigningMap), BindingFlags.Public | BindingFlags.Static);
var field = mainclass.GetValue(null) as Dictionary<string, int>;
if (field != null)
{
field["RS256"] = 512;
}
var mainclass2 = typeof(AsymmetricSignatureProvider).GetField(nameof(AsymmetricSignatureProvider.DefaultMinimumAsymmetricKeySizeInBitsForVerifyingMap), BindingFlags.Public | BindingFlags.Static);
var field2 = mainclass2.GetValue(null) as Dictionary<string, int>;
if (field2 != null)
{
field2["RS256"] = 512;
}

Create/Convert to CMS/pkcs7 Certificate from Certificate collection and save it as p7b

I'm trying to convert/Create a PKCS7 "p7b" Certificate from signed certificate pem + chain using BouncyCastle or .net Cryptography class
I tried to use only BC without success, so I use BC only to read pem certs and then transform it to an X509Certificate2 object. What I'm looking for at the end is a pem string at the end starting with "-----BEGIN PKCS7-----" to save it as p7b file
what have I done..
public void DownloadP7bFile(string certId)
{
var records = (DataView)myCertDataSource.Select(DataSourceSelectArguments.Empty);
var selected = Guid.Parse(certId);
foreach (DataRow row in records.Table.Rows)
{
if (!Guid.Parse(row.Field<Guid>("cert_id").ToString()).Equals(selected)) continue;
var filename = row.Field<string>("cert_fqdn_main");
var certContent2 = row.Field<string>("certHash_certificate");
var certissuer = row.Field<string>("certHash_issuer");
DataTable chaincerts = GetChainCertsFromDB(certissuer);
//### get pem string from DB to BC cert objects
Org.BouncyCastle.X509.X509Certificate serverCert = CreateCertObjFromPem(certContent2);
Org.BouncyCastle.X509.X509Certificate interCert = CreateCertObjFromPem(chaincerts.Rows[0].Field<string>("cacert_pemhash"));
Org.BouncyCastle.X509.X509Certificate rootCert = CreateCertObjFromPem(chaincerts.Rows[1].Field<string>("cacert_pemhash"));
//### transform to X509Certificate2 object
System.Security.Cryptography.X509Certificates.X509Certificate2 serverCert2 = new System.Security.Cryptography.X509Certificates.X509Certificate2();
System.Security.Cryptography.X509Certificates.X509Certificate2 interCert2 = new System.Security.Cryptography.X509Certificates.X509Certificate2();
System.Security.Cryptography.X509Certificates.X509Certificate2 rootCert2 = new System.Security.Cryptography.X509Certificates.X509Certificate2();
serverCert2.Import(serverCert.GetEncoded());
interCert2.Import(interCert.GetEncoded());
rootCert2.Import(rootCert.GetEncoded());
//### collect all needed certificates
var collection = new System.Security.Cryptography.X509Certificates.X509Certificate2Collection();
collection.Add(rootCert2);
collection.Add(interCert2);
collection.Add(serverCert2);
var pkcs7ContentBytes = collection.Export(System.Security.Cryptography.X509Certificates.X509ContentType.Pkcs7);
//### Test if pkcs7 can be read ###
System.Security.Cryptography.Pkcs.SignedCms sigcms = new System.Security.Cryptography.Pkcs.SignedCms();
sigcms.Decode(pkcs7ContentBytes);
if (sigcms.Certificates.Count > 0)
{
Console.WriteLine("Aussteller: {0}", sigcms.Certificates[0].IssuerName.Name);
Console.WriteLine("Gültig bis {0}", sigcms.Certificates[0].NotAfter);
}
var sigvar2 = sigcms.Encode();
var pkcs7Content = Convert.ToBase64String(pkcs7ContentBytes); //das gute
var certEncodedBytes = Convert.FromBase64String(pkcs7Content);
var certContent = Encoding.UTF8.GetString(certEncodedBytes);
var certContent7 = UTF8Encoding.UTF8.GetString(certEncodedBytes);
var CertContent8 = Convert.ToBase64String(sigvar2);
var CertContent8Bytes = Convert.FromBase64String(CertContent8);
var certfromsig = sigcms.Certificates.Export(System.Security.Cryptography.X509Certificates.X509ContentType.Pkcs7);
//var pkcs7cert = new System.Security.Cryptography.X509Certificates.X509Certificate2(certEncodedBytes);
//var pkcs7cert2 = new System.Security.Cryptography.X509Certificates.X509Certificate2(sigvar2);
//System.Security.Cryptography.Pkcs.EnvelopedCms pkcs7Envelop = new System.Security.Cryptography.Pkcs.EnvelopedCms();
//File.WriteAllBytes(#"")
//string utfString = Encoding.UTF8.GetString(pkcs7ContentBytes, 0, pkcs7ContentBytes.Length);
var memoryStream = new MemoryStream(certEncodedBytes);
//var cryptostream = new System.Security.Cryptography.CryptoStream(memoryStream);
//memoryStream.Write(pkcs7ContentBytes, 0, pkcs7ContentBytes.Length);
var test31 = memoryStream.ToArray();
var test32 = memoryStream.Read(certEncodedBytes, 0, certEncodedBytes.Length);
memoryStream.Flush();
memoryStream.Close();
//var test30 = DecoderConverter.ConvertX509ToPkcs7(rootCert, interCert, serverCert);
PerformFileDownload(filename, "p7b", pkcs7Content);
break;
}
}

upload to S3 with BOM

I want to upload file to S3 with BOM. How can I do this?
var transferUtility = new TransferUtility(client);
string content = "hello";
byte[] b = DefaultEncoding.GetBytes(content);
using (var fileStream = new MemoryStream(b))
{
var request = new TransferUtilityUploadRequest
{
BucketName = bucket,
InputStream = fileStream,
Key = NormalizePath(Path.Combine(folder, file.Name)),
};
}
transferUtility.Upload(request);
When I download file from S3 it's UTF-8, but not UTF-8-BOM
var transferUtility = new TransferUtility(client);
string content = "hello";
byte[] b = Encoding.UTF8.GetPreamble().Concat(DefaultEncoding.GetBytes(content)).ToArray();
using (var fileStream = new MemoryStream(b))
{
var request = new TransferUtilityUploadRequest
{
BucketName = bucket,
InputStream = fileStream,
Key = NormalizePath(Path.Combine(folder, file.Name)),
};
}
transferUtility.Upload(request);

How to bind XML data using XMLModel?

setXml: function(){
oXMLModel = new sap.ui.model.xml.XMLModel();
var sXML ="<res><SolutionsResponse><SolList><Solution><SupportedMobileDetails><SupportedMobileDetail><SupportedMobileDevice>Smartphone</SupportedMobileDevice><SupportedMobileOS>Blackberry</SupportedMobileOS><Version>6</Version><StatusDescription>Productive</StatusDescription><SupportedMobileURL>https://hxi-cust802.dev.sapbydesign.com/sap/cpa/ui/esdownloads/0194814131_0/Smartphone_Blackberry_2.0/SalesService.zip</SupportedMobileURL><SupportedMobileDeviceCode>2</SupportedMobileDeviceCode><SupportedMobileOSCode>4</SupportedMobileOSCode></SupportedMobileDetail></SupportedMobileDetails></Solution><Solution><SupportedMobileDetails><SupportedMobileDetail><SupportedMobileDevice>Tablet</SupportedMobileDevice><SupportedMobileOS>ios</SupportedMobileOS><Version>6</Version><StatusDescription>New</StatusDescription><SupportedMobileURL>https://hxi-cust802.dev.sapbydesign.com/sap/cpa/ui/esdownloads/0194814131_0/Smartphone_Blackberry_2.0/SalesService.zip</SupportedMobileURL><SupportedMobileDeviceCode>2</SupportedMobileDeviceCode><SupportedMobileOSCode>4</SupportedMobileOSCode></SupportedMobileDetail></SupportedMobileDetails></Solution><Solution><SupportedMobileDetails><SupportedMobileDetail><SupportedMobileDevice>Tablet</SupportedMobileDevice><SupportedMobileOS>ios</SupportedMobileOS><Version>6</Version><StatusDescription>New</StatusDescription><SupportedMobileURL>https://hxi-cust802.dev.sapbydesign.com/sap/cpa/ui/esdownloads/0194814131_0/Smartphone_Blackberry_2.0/SalesService.zip</SupportedMobileURL><SupportedMobileDeviceCode>2</SupportedMobileDeviceCode><SupportedMobileOSCode>4</SupportedMobileOSCode></SupportedMobileDetail><SupportedMobileDetail><SupportedMobileDevice>SmartPhone</SupportedMobileDevice><SupportedMobileOS>ios</SupportedMobileOS><Version>6</Version><StatusDescription>New</StatusDescription><SupportedMobileURL>https://hxi-cust802.dev.sapbydesign.com/sap/cpa/ui/esdownloads/0194814131_0/Smartphone_Blackberry_2.0/SalesService.zip</SupportedMobileURL><SupportedMobileDeviceCode>2</SupportedMobileDeviceCode><SupportedMobileOSCode>4</SupportedMobileOSCode></SupportedMobileDetail></SupportedMobileDetails></Solution></SolList></SolutionsResponse></res>";
this.oModel = sap.ui.getCore().getModel(this.oController.sModelId);
this.oModel.setXML(sXML);
sap.ui.getCore().byId('rr1').setModel(this.oModel);
},
var oSixthCell = new sap.ui.commons.layout.MatrixLayoutCell();
var omainLayout = new sap.ui.commons.layout.HorizontalLayout('main');
var oRowRepeater = new sap.ui.commons.RowRepeater("rr1");
var matrixRow, matrixCell, control;
var oRowTemplate = new sap.ui.commons.layout.MatrixLayout("template");
matrixRow = new sap.ui.commons.layout.MatrixLayoutRow();
control = new sap.ui.commons.Link({
press: function() {
control = new sap.ui.commons.Link({
press: function() {
control = new sap.ui.commons.Link({
press: function() {
control = new sap.ui.commons.Link();
control.bindProperty("text","type");
matrixCell = new sap.ui.commons.layout.MatrixLayoutCell();
matrixCell.addContent(control);
matrixRow.addCell(matrixCell);
}
});
control.bindProperty("text","version");
matrixCell = new sap.ui.commons.layout.MatrixLayoutCell();
matrixCell.addContent(control);
matrixRow.addCell(matrixCell);
}
});
control.bindProperty("text","os");
matrixCell = new sap.ui.commons.layout.MatrixLayoutCell();
matrixCell.addContent(control);
matrixRow.addCell(matrixCell);
}
});
control.bindProperty("text","/SupportedMobileDetail/SupportedMobileDevice");
matrixCell = new sap.ui.commons.layout.MatrixLayoutCell();
matrixCell.addContent(control);
matrixRow.addCell(matrixCell);
this.setXml();
var sXMl = this.oModel.getXML();
var sXMLOS = new sap.cp.core.util.XMLUtil(sXMl);
oVarXmlModelOS= new sap.ui.model.xml.XMLModel();
oVarXmlModelOS.setSizeLimit(5000);
oVarXmlModelOS.setXML(jQuery.sap.serializeXML(sXMLOS.Find('Solution')[0]));
omainLayout.setModel(oVarXmlModelOS);
oRowRepeater.bindRows("/", oRowTemplate);
omainLayout.addContent(oRowRepeater);
oSixthCell.addContent(omainLayout);
oDownloadTrialLayout.createRow(oSixthCell);
I'm creating a SAPUI5 application with XML data to be bind. I need some help in binding the XML to my structure.