mirror of
https://github.com/NecroticBamboo/QRBee.git
synced 2025-12-21 12:11:53 +00:00
Encrypted Client card data block added. Android public and private keeys separated into different files.
This commit is contained in:
parent
81a87262c5
commit
4722585e17
@ -2,49 +2,20 @@
|
|||||||
{
|
{
|
||||||
public class ClientCardData
|
public class ClientCardData
|
||||||
{
|
{
|
||||||
|
public string TransactionId { get; set; }
|
||||||
public string CardNumber
|
public string CardNumber { get; set; }
|
||||||
{
|
public string ExpirationDateMMYY { get; set; }
|
||||||
get;
|
public string ValidFrom { get; set; }
|
||||||
set;
|
public string CardHolderName { get; set; }
|
||||||
}
|
public string CVC { get; set; }
|
||||||
|
public int? IssueNo { get; set; }
|
||||||
public string ExpirationDateMMYY
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string ValidFrom
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string CardHolderName
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string CVC
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int? IssueNo
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Convert ClientCardData to string to be used as a source for encryption.
|
/// Convert ClientCardData to string to be used as a source for encryption.
|
||||||
/// WARNING: this should always be encrypted and never transmitted in clear text form.
|
/// WARNING: this should always be encrypted and never transmitted in clear text form.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Converted string</returns>
|
/// <returns>Converted string</returns>
|
||||||
public string AsString() => $"{CardNumber}|{ExpirationDateMMYY}|{ValidFrom}|{CardHolderName}|{CVC}|{IssueNo}";
|
public string AsString() => $"{TransactionId}|{CardNumber}|{ExpirationDateMMYY}|{ValidFrom}|{CardHolderName}|{CVC}|{IssueNo}";
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,7 +12,13 @@ namespace QRBee.Core.Data
|
|||||||
set;
|
set;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Certificate
|
public string ClientCertificate
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string APIServerCertificate
|
||||||
{
|
{
|
||||||
get;
|
get;
|
||||||
set;
|
set;
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using System.Security.Cryptography.X509Certificates;
|
using System.Security.Cryptography;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
|
|
||||||
namespace QRBee.Core.Security
|
namespace QRBee.Core.Security
|
||||||
{
|
{
|
||||||
@ -38,6 +39,12 @@ namespace QRBee.Core.Security
|
|||||||
/// self-signed until CA issues a proper certificate
|
/// self-signed until CA issues a proper certificate
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
X509Certificate2 LoadPrivateKey();
|
RSA LoadPrivateKey();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get public key certificate
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Public key certificate</returns>
|
||||||
|
X509Certificate2 GetCertificate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -47,6 +47,11 @@ namespace QRBee.Core.Security
|
|||||||
|
|
||||||
// -------------------------- certificate services --------------------------
|
// -------------------------- certificate services --------------------------
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// API Server certificate
|
||||||
|
/// </summary>
|
||||||
|
X509Certificate2 APIServerCertificate { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Convert binary block to X509Certificate2.
|
/// Convert binary block to X509Certificate2.
|
||||||
/// <see cref="X509Certificate2.CreateFromPem"/>
|
/// <see cref="X509Certificate2.CreateFromPem"/>
|
||||||
|
|||||||
@ -39,12 +39,13 @@ namespace QRBee.Core.Security
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public byte[] Decrypt(byte[] data)
|
public byte[] Decrypt(byte[] data)
|
||||||
{
|
{
|
||||||
using var myCert = LoadPrivateKey();
|
using var rsa = LoadPrivateKey();
|
||||||
using var rsa = myCert.GetRSAPrivateKey();
|
|
||||||
var res = rsa?.Decrypt(data, RSAEncryptionPadding.Pkcs1) ?? throw new CryptographicException("No private key found");
|
var res = rsa?.Decrypt(data, RSAEncryptionPadding.Pkcs1) ?? throw new CryptographicException("No private key found");
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract X509Certificate2 APIServerCertificate { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public byte [] Encrypt(byte[] data, X509Certificate2 destCert)
|
public byte [] Encrypt(byte[] data, X509Certificate2 destCert)
|
||||||
{
|
{
|
||||||
@ -63,8 +64,7 @@ namespace QRBee.Core.Security
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public byte[] Sign(byte[] data)
|
public byte[] Sign(byte[] data)
|
||||||
{
|
{
|
||||||
using var myCert = LoadPrivateKey();
|
using var rsa = LoadPrivateKey();
|
||||||
using var rsa = myCert.GetRSAPrivateKey();
|
|
||||||
var res = rsa?.SignData(data, 0, data.Length, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1) ?? throw new CryptographicException("No private key found");
|
var res = rsa?.SignData(data, 0, data.Length, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1) ?? throw new CryptographicException("No private key found");
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -86,16 +86,12 @@ namespace QRBee.Core.Security
|
|||||||
return serNo;
|
return serNo;
|
||||||
}
|
}
|
||||||
|
|
||||||
private X509Certificate2 LoadPrivateKey()
|
private RSA LoadPrivateKey()
|
||||||
{
|
{
|
||||||
if (!PrivateKeyHandler.Exists())
|
if (!PrivateKeyHandler.Exists())
|
||||||
PrivateKeyHandler.GeneratePrivateKey(); //TODO: subject name
|
PrivateKeyHandler.GeneratePrivateKey(); //TODO: subject name
|
||||||
|
|
||||||
var pk = PrivateKeyHandler.LoadPrivateKey();
|
var pk = PrivateKeyHandler.LoadPrivateKey();
|
||||||
if (!IsValid(pk) )
|
|
||||||
{
|
|
||||||
throw new CryptographicException("CA private key is not valid");
|
|
||||||
}
|
|
||||||
|
|
||||||
return pk;
|
return pk;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -81,7 +81,7 @@ namespace QRBee.Droid.Services
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ReadableCertificateRequest CreateCertificateRequest(string subjectName)
|
public ReadableCertificateRequest CreateCertificateRequest(string subjectName)
|
||||||
{
|
{
|
||||||
using var rsa = LoadRsaPrivateKey();
|
using var rsa = LoadPrivateKey();
|
||||||
|
|
||||||
var request = new ReadableCertificateRequest
|
var request = new ReadableCertificateRequest
|
||||||
{
|
{
|
||||||
@ -96,85 +96,68 @@ namespace QRBee.Droid.Services
|
|||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
///// <summary>
|
||||||
/// Generate EXPORTABLE certificate
|
///// Generate EXPORTABLE certificate
|
||||||
/// </summary>
|
///// </summary>
|
||||||
/// <param name="subjectName"></param>
|
///// <param name="subjectName"></param>
|
||||||
/// <returns></returns>
|
///// <returns></returns>
|
||||||
private X509Certificate2 CreateSelfSignedClientCertificate(string subjectName)
|
//private X509Certificate2 CreateSelfSignedClientCertificate(string subjectName)
|
||||||
|
//{
|
||||||
|
// // https://stackoverflow.com/questions/42786986/how-to-create-a-valid-self-signed-x509certificate2-programmatically-not-loadin
|
||||||
|
|
||||||
|
// var distinguishedName = new X500DistinguishedName($"CN={subjectName}");
|
||||||
|
|
||||||
|
// using var rsa = RSA.Create(RSABits);
|
||||||
|
// var request = CreateRequest(distinguishedName, rsa);
|
||||||
|
|
||||||
|
// var certificate = request.CreateSelfSigned(
|
||||||
|
// new DateTimeOffset(DateTime.UtcNow.AddDays(-1)),
|
||||||
|
// new DateTimeOffset(DateTime.UtcNow.AddDays(CertificateValidityDays))
|
||||||
|
// );
|
||||||
|
|
||||||
|
// return certificate;
|
||||||
|
//}
|
||||||
|
|
||||||
|
///// <summary>
|
||||||
|
///// Generate CA certificate request (i.e. with KeyCertSign usage extension)
|
||||||
|
///// </summary>
|
||||||
|
///// <param name="distinguishedName"></param>
|
||||||
|
///// <param name="rsa"></param>
|
||||||
|
///// <returns></returns>
|
||||||
|
//private static CertificateRequest CreateRequest(X500DistinguishedName distinguishedName, RSA rsa)
|
||||||
|
//{
|
||||||
|
// //TODO not supported on Android
|
||||||
|
// var request = new CertificateRequest(
|
||||||
|
// distinguishedName,
|
||||||
|
// rsa,
|
||||||
|
// HashAlgorithmName.SHA256,
|
||||||
|
// RSASignaturePadding.Pkcs1
|
||||||
|
// );
|
||||||
|
|
||||||
|
// request.CertificateExtensions.Add(
|
||||||
|
// new X509KeyUsageExtension(
|
||||||
|
// X509KeyUsageFlags.DataEncipherment
|
||||||
|
// | X509KeyUsageFlags.KeyEncipherment
|
||||||
|
// | X509KeyUsageFlags.DigitalSignature,
|
||||||
|
// false));
|
||||||
|
|
||||||
|
// return request;
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
|
public X509Certificate2 GetCertificate()
|
||||||
{
|
{
|
||||||
// https://stackoverflow.com/questions/42786986/how-to-create-a-valid-self-signed-x509certificate2-programmatically-not-loadin
|
|
||||||
|
|
||||||
var distinguishedName = new X500DistinguishedName($"CN={subjectName}");
|
var cert = new X509Certificate2(PrivateKeyFileName);
|
||||||
|
return cert;
|
||||||
using var rsa = RSA.Create(RSABits);
|
|
||||||
var request = CreateRequest(distinguishedName, rsa);
|
|
||||||
|
|
||||||
var certificate = request.CreateSelfSigned(
|
|
||||||
new DateTimeOffset(DateTime.UtcNow.AddDays(-1)),
|
|
||||||
new DateTimeOffset(DateTime.UtcNow.AddDays(CertificateValidityDays))
|
|
||||||
);
|
|
||||||
|
|
||||||
return certificate;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generate CA certificate request (i.e. with KeyCertSign usage extension)
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="distinguishedName"></param>
|
|
||||||
/// <param name="rsa"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private static CertificateRequest CreateRequest(X500DistinguishedName distinguishedName, RSA rsa)
|
|
||||||
{
|
|
||||||
//TODO not supported on Android
|
|
||||||
var request = new CertificateRequest(
|
|
||||||
distinguishedName,
|
|
||||||
rsa,
|
|
||||||
HashAlgorithmName.SHA256,
|
|
||||||
RSASignaturePadding.Pkcs1
|
|
||||||
);
|
|
||||||
|
|
||||||
request.CertificateExtensions.Add(
|
|
||||||
new X509KeyUsageExtension(
|
|
||||||
X509KeyUsageFlags.DataEncipherment
|
|
||||||
| X509KeyUsageFlags.KeyEncipherment
|
|
||||||
| X509KeyUsageFlags.DigitalSignature,
|
|
||||||
false));
|
|
||||||
|
|
||||||
return request;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public X509Certificate2 LoadPrivateKey()
|
|
||||||
{
|
|
||||||
if (_certificate != null)
|
|
||||||
return _certificate;
|
|
||||||
|
|
||||||
// double locking
|
|
||||||
lock ( _syncObject )
|
|
||||||
{
|
|
||||||
if (_certificate != null)
|
|
||||||
return _certificate;
|
|
||||||
|
|
||||||
if (!Exists())
|
|
||||||
throw new CryptographicException("PrivateKey does not exist");
|
|
||||||
|
|
||||||
_certificate = new X509Certificate2(PrivateKeyFileName, VeryBadNeverUsePrivateKeyPassword);
|
|
||||||
return _certificate;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void AttachCertificate(X509Certificate2 cert)
|
public void AttachCertificate(X509Certificate2 cert)
|
||||||
{
|
{
|
||||||
// heavily modified version of:
|
var bytes = cert.Export(X509ContentType.Cert);
|
||||||
// https://stackoverflow.com/questions/18462064/associate-a-private-key-with-the-x509certificate2-class-in-net
|
|
||||||
using var rsa = LoadRsaPrivateKey();
|
|
||||||
|
|
||||||
var newPk = cert.CopyWithPrivateKey(rsa);
|
File.WriteAllBytes(PrivateKeyFileName, bytes);
|
||||||
|
|
||||||
var pkcs12data = newPk.Export(X509ContentType.Pfx, VeryBadNeverUsePrivateKeyPassword);
|
|
||||||
File.WriteAllBytes(PrivateKeyFileName, pkcs12data);
|
|
||||||
|
|
||||||
lock ( _syncObject )
|
lock ( _syncObject )
|
||||||
{
|
{
|
||||||
@ -184,7 +167,7 @@ namespace QRBee.Droid.Services
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private RSA LoadRsaPrivateKey()
|
public RSA LoadPrivateKey()
|
||||||
{
|
{
|
||||||
var bytes = File.ReadAllBytes(PrivateRsaKeyFileName);
|
var bytes = File.ReadAllBytes(PrivateRsaKeyFileName);
|
||||||
var s = CryptoHelper.DecryptStringAES(bytes, VeryBadNeverUsePrivateKeyPassword);
|
var s = CryptoHelper.DecryptStringAES(bytes, VeryBadNeverUsePrivateKeyPassword);
|
||||||
|
|||||||
@ -1,12 +1,15 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Security.Cryptography.X509Certificates;
|
using System.Security.Cryptography.X509Certificates;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.IO;
|
||||||
using QRBee.Core.Security;
|
using QRBee.Core.Security;
|
||||||
|
|
||||||
namespace QRBee.Droid.Services
|
namespace QRBee.Droid.Services
|
||||||
{
|
{
|
||||||
internal class AndroidSecurityService : SecurityServiceBase
|
internal class AndroidSecurityService : SecurityServiceBase
|
||||||
{
|
{
|
||||||
|
private X509Certificate2 _apiServerCertificate;
|
||||||
|
private string ApiServerCertificateFileName => $"{Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData)}/ApiServerCertificate.bin";
|
||||||
|
|
||||||
public AndroidSecurityService(IPrivateKeyHandler privateKeyHandler)
|
public AndroidSecurityService(IPrivateKeyHandler privateKeyHandler)
|
||||||
: base(privateKeyHandler)
|
: base(privateKeyHandler)
|
||||||
@ -51,6 +54,29 @@ namespace QRBee.Droid.Services
|
|||||||
|
|
||||||
return builder.ToString();
|
return builder.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override X509Certificate2 APIServerCertificate
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_apiServerCertificate != null)
|
||||||
|
{
|
||||||
|
return _apiServerCertificate;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!File.Exists(ApiServerCertificateFileName))
|
||||||
|
throw new ApplicationException($"File not found: {ApiServerCertificateFileName}");
|
||||||
|
var bytes = File.ReadAllBytes(ApiServerCertificateFileName);
|
||||||
|
_apiServerCertificate = new X509Certificate2(bytes);
|
||||||
|
return _apiServerCertificate;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_apiServerCertificate = value;
|
||||||
|
var bytes = _apiServerCertificate.Export(X509ContentType.Cert);
|
||||||
|
File.WriteAllBytes(ApiServerCertificateFileName,bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,7 @@ namespace QRBee.Services
|
|||||||
{
|
{
|
||||||
public class Settings
|
public class Settings
|
||||||
{
|
{
|
||||||
//TODO add ClientId
|
|
||||||
public string ClientId { get; set; }
|
public string ClientId { get; set; }
|
||||||
public string PIN { get; set; }
|
public string PIN { get; set; }
|
||||||
public bool IsRegistered => !string.IsNullOrWhiteSpace(ClientId);
|
public bool IsRegistered => !string.IsNullOrWhiteSpace(ClientId);
|
||||||
@ -20,7 +20,7 @@ namespace QRBee.Services
|
|||||||
public string ExpirationDate { get; set; }
|
public string ExpirationDate { get; set; }
|
||||||
public string CardHolderName { get; set; }
|
public string CardHolderName { get; set; }
|
||||||
public string CVC { get; set; }
|
public string CVC { get; set; }
|
||||||
public string IssueNo { get; set; }
|
public int? IssueNo { get; set; }
|
||||||
public string Password { get; set; }
|
public string Password { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -12,6 +12,7 @@ namespace QRBee.ViewModels
|
|||||||
{
|
{
|
||||||
private readonly IQRScanner _scanner;
|
private readonly IQRScanner _scanner;
|
||||||
private readonly ISecurityService _securityService;
|
private readonly ISecurityService _securityService;
|
||||||
|
private readonly ILocalSettings _localSettings;
|
||||||
public bool _isAcceptDenyButtonVisible;
|
public bool _isAcceptDenyButtonVisible;
|
||||||
public bool _isQrVisible;
|
public bool _isQrVisible;
|
||||||
public bool _isScanButtonVisible;
|
public bool _isScanButtonVisible;
|
||||||
@ -21,10 +22,11 @@ namespace QRBee.ViewModels
|
|||||||
private string _qrCode;
|
private string _qrCode;
|
||||||
private MerchantToClientRequest _merchantToClientRequest;
|
private MerchantToClientRequest _merchantToClientRequest;
|
||||||
|
|
||||||
public ClientPageViewModel(IQRScanner scanner, ISecurityService securityService)
|
public ClientPageViewModel(IQRScanner scanner, ISecurityService securityService, ILocalSettings localSettings)
|
||||||
{
|
{
|
||||||
_scanner = scanner;
|
_scanner = scanner;
|
||||||
_securityService = securityService;
|
_securityService = securityService;
|
||||||
|
_localSettings = localSettings;
|
||||||
ScanCommand = new Command(OnScanButtonClicked);
|
ScanCommand = new Command(OnScanButtonClicked);
|
||||||
AcceptQrCommand = new Command(OnAcceptQrCommand);
|
AcceptQrCommand = new Command(OnAcceptQrCommand);
|
||||||
DenyQrCommand = new Command(OnDenyQrCommand);
|
DenyQrCommand = new Command(OnDenyQrCommand);
|
||||||
@ -149,16 +151,14 @@ namespace QRBee.ViewModels
|
|||||||
|
|
||||||
var answer = await Application.Current.MainPage.DisplayAlert("Confirmation", "Would you like to accept the offer?", "Yes", "No");
|
var answer = await Application.Current.MainPage.DisplayAlert("Confirmation", "Would you like to accept the offer?", "Yes", "No");
|
||||||
if (!answer) return;
|
if (!answer) return;
|
||||||
|
var settings = _localSettings.LoadSettings();
|
||||||
var response = new ClientToMerchantResponse
|
var response = new ClientToMerchantResponse
|
||||||
{
|
{
|
||||||
//TODO get client id from database
|
ClientId = settings.ClientId,
|
||||||
ClientId = Guid.NewGuid().ToString("D"),
|
|
||||||
TimeStampUTC = DateTime.UtcNow,
|
TimeStampUTC = DateTime.UtcNow,
|
||||||
MerchantRequest = _merchantToClientRequest
|
MerchantRequest = _merchantToClientRequest,
|
||||||
|
EncryptedClientCardData = EncryptCardData(settings, _merchantToClientRequest.MerchantTransactionId)
|
||||||
};
|
};
|
||||||
// TODO Create client signature.
|
|
||||||
var clientSignature = _securityService.Sign(Encoding.UTF8.GetBytes(response.AsDataForSignature()));
|
var clientSignature = _securityService.Sign(Encoding.UTF8.GetBytes(response.AsDataForSignature()));
|
||||||
response.ClientSignature = Convert.ToBase64String(clientSignature);
|
response.ClientSignature = Convert.ToBase64String(clientSignature);
|
||||||
|
|
||||||
@ -168,6 +168,23 @@ namespace QRBee.ViewModels
|
|||||||
IsScanButtonVisible = true;
|
IsScanButtonVisible = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string EncryptCardData(Settings settings, string transactionId)
|
||||||
|
{
|
||||||
|
var clientCardData = new ClientCardData
|
||||||
|
{
|
||||||
|
TransactionId = transactionId,
|
||||||
|
CardNumber = settings.CardNumber,
|
||||||
|
ExpirationDateMMYY = settings.ExpirationDate,
|
||||||
|
ValidFrom = settings.ValidFrom,
|
||||||
|
CardHolderName = settings.CardHolderName,
|
||||||
|
CVC = settings.CVC,
|
||||||
|
IssueNo = settings.IssueNo
|
||||||
|
};
|
||||||
|
|
||||||
|
var bytes = _securityService.Encrypt(Encoding.UTF8.GetBytes(clientCardData.AsString()),_securityService.APIServerCertificate);
|
||||||
|
return Convert.ToBase64String(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
public void OnDenyQrCommand(object obj)
|
public void OnDenyQrCommand(object obj)
|
||||||
{
|
{
|
||||||
QrCode = null;
|
QrCode = null;
|
||||||
|
|||||||
@ -131,8 +131,7 @@ namespace QRBee.ViewModels
|
|||||||
{
|
{
|
||||||
var trans = new MerchantToClientRequest
|
var trans = new MerchantToClientRequest
|
||||||
{
|
{
|
||||||
//TODO get merchant id from database
|
MerchantId = _settings.LoadSettings().ClientId,
|
||||||
MerchantId = Guid.NewGuid().ToString("D"),
|
|
||||||
MerchantTransactionId = Guid.NewGuid().ToString("D"),
|
MerchantTransactionId = Guid.NewGuid().ToString("D"),
|
||||||
Name = Name,
|
Name = Name,
|
||||||
Amount = Amount,
|
Amount = Amount,
|
||||||
|
|||||||
@ -50,7 +50,7 @@ namespace QRBee.ViewModels
|
|||||||
public string ExpirationDate { get; set; }
|
public string ExpirationDate { get; set; }
|
||||||
public string CardHolderName { get; set; }
|
public string CardHolderName { get; set; }
|
||||||
public string CVC { get; set; }
|
public string CVC { get; set; }
|
||||||
public string IssueNo { get; set; }
|
public int? IssueNo { get; set; }
|
||||||
|
|
||||||
public Color Password1Color { get; set; }
|
public Color Password1Color { get; set; }
|
||||||
public Color Password2Color { get; set;}
|
public Color Password2Color { get; set;}
|
||||||
@ -125,7 +125,7 @@ namespace QRBee.ViewModels
|
|||||||
|
|
||||||
await _settings.SaveSettings(settings);
|
await _settings.SaveSettings(settings);
|
||||||
|
|
||||||
if (!_privateKeyHandler.Exists())
|
//if (!_privateKeyHandler.Exists())
|
||||||
{
|
{
|
||||||
_privateKeyHandler.GeneratePrivateKey(settings.Name);
|
_privateKeyHandler.GeneratePrivateKey(settings.Name);
|
||||||
}
|
}
|
||||||
@ -149,6 +149,7 @@ namespace QRBee.ViewModels
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
//TODO Register if not, otherwise update
|
||||||
// FOR TESTING PURPOSES
|
// FOR TESTING PURPOSES
|
||||||
//!settings.IsRegistered
|
//!settings.IsRegistered
|
||||||
if (true)
|
if (true)
|
||||||
@ -158,10 +159,14 @@ namespace QRBee.ViewModels
|
|||||||
// Save ClientId to LocalSettings
|
// Save ClientId to LocalSettings
|
||||||
settings = _settings.LoadSettings();
|
settings = _settings.LoadSettings();
|
||||||
settings.ClientId = response.ClientId;
|
settings.ClientId = response.ClientId;
|
||||||
|
|
||||||
|
// Save server public key certificate
|
||||||
|
_securityService.APIServerCertificate = _securityService.Deserialize(response.APIServerCertificate);
|
||||||
|
|
||||||
await _settings.SaveSettings(settings);
|
await _settings.SaveSettings(settings);
|
||||||
|
|
||||||
// Attach certificate to privateKey (replace self-sighed with server issued certificate)
|
// Attach certificate to privateKey (replace self-sighed with server issued certificate)
|
||||||
_privateKeyHandler.AttachCertificate(_securityService.Deserialize(response.Certificate));
|
_privateKeyHandler.AttachCertificate(_securityService.Deserialize(response.ClientCertificate));
|
||||||
|
|
||||||
var page = Application.Current.MainPage.Navigation.NavigationStack.LastOrDefault();
|
var page = Application.Current.MainPage.Navigation.NavigationStack.LastOrDefault();
|
||||||
await page.DisplayAlert("Success", "You have been registered successfully", "Ok");
|
await page.DisplayAlert("Success", "You have been registered successfully", "Ok");
|
||||||
|
|||||||
@ -62,7 +62,8 @@ namespace QRBee.Api.Services
|
|||||||
return new RegistrationResponse
|
return new RegistrationResponse
|
||||||
{
|
{
|
||||||
ClientId = clientId,
|
ClientId = clientId,
|
||||||
Certificate = _securityService.Serialize(clientCertificate)
|
ClientCertificate = _securityService.Serialize(clientCertificate),
|
||||||
|
APIServerCertificate = _securityService.Serialize(_securityService.APIServerCertificate)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -29,7 +29,10 @@ namespace QRBee.Api.Services
|
|||||||
var req = CreateClientCertRequest(distinguishedName, rsa);
|
var req = CreateClientCertRequest(distinguishedName, rsa);
|
||||||
|
|
||||||
var pk = PrivateKeyHandler.LoadPrivateKey();
|
var pk = PrivateKeyHandler.LoadPrivateKey();
|
||||||
var clientCert = req.Create(pk,
|
var cert = PrivateKeyHandler.GetCertificate();
|
||||||
|
var newCert = cert.CopyWithPrivateKey(pk);
|
||||||
|
|
||||||
|
var clientCert = req.Create(newCert,
|
||||||
DateTimeOffset.UtcNow - TimeSpan.FromDays(1),
|
DateTimeOffset.UtcNow - TimeSpan.FromDays(1),
|
||||||
DateTimeOffset.UtcNow + TimeSpan.FromDays(CertificateValidityPeriodDays),
|
DateTimeOffset.UtcNow + TimeSpan.FromDays(CertificateValidityPeriodDays),
|
||||||
Guid.NewGuid()
|
Guid.NewGuid()
|
||||||
@ -92,6 +95,13 @@ namespace QRBee.Api.Services
|
|||||||
|
|
||||||
return builder.ToString();
|
return builder.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override X509Certificate2 APIServerCertificate
|
||||||
|
{
|
||||||
|
get => PrivateKeyHandler.GetCertificate();
|
||||||
|
set => throw new ApplicationException("Do not call this");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -55,7 +55,7 @@ namespace QRBee.Api.Services
|
|||||||
public ReadableCertificateRequest CreateCertificateRequest(string subjectName)
|
public ReadableCertificateRequest CreateCertificateRequest(string subjectName)
|
||||||
{
|
{
|
||||||
//TODO in fact server should create certificate request in standard format if we ever want to get externally sighed certificate.
|
//TODO in fact server should create certificate request in standard format if we ever want to get externally sighed certificate.
|
||||||
var pk = LoadPrivateKey();
|
var pk = Load();
|
||||||
var rsa = pk.GetRSAPrivateKey();
|
var rsa = pk.GetRSAPrivateKey();
|
||||||
|
|
||||||
if (rsa == null)
|
if (rsa == null)
|
||||||
@ -172,7 +172,7 @@ namespace QRBee.Api.Services
|
|||||||
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public X509Certificate2 LoadPrivateKey()
|
private X509Certificate2 Load()
|
||||||
{
|
{
|
||||||
if (_certificate != null)
|
if (_certificate != null)
|
||||||
return _certificate;
|
return _certificate;
|
||||||
@ -191,6 +191,20 @@ namespace QRBee.Api.Services
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RSA LoadPrivateKey()
|
||||||
|
{
|
||||||
|
var pk = Load();
|
||||||
|
return pk.GetRSAPrivateKey()?? throw new ApplicationException("Private key not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
public X509Certificate2 GetCertificate()
|
||||||
|
{
|
||||||
|
var pk = Load();
|
||||||
|
var bytes = pk.Export(X509ContentType.Cert);
|
||||||
|
var cert = new X509Certificate2(bytes);
|
||||||
|
return cert;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void AttachCertificate(X509Certificate2 cert)
|
public void AttachCertificate(X509Certificate2 cert)
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user