Skip to content
This repository was archived by the owner on Dec 24, 2022. It is now read-only.

Commit 371a6c1

Browse files
committed
internalize license key verification
1 parent a0c45fb commit 371a6c1

File tree

2 files changed

+193
-100
lines changed

2 files changed

+193
-100
lines changed

src/ServiceStack.Text/LicenseUtils.cs

Lines changed: 192 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -164,12 +164,18 @@ public static void AssertEvaluationLicense()
164164

165165
private static readonly int[] revokedSubs = { 4018, 4019, 4041, 4331, 4581 };
166166

167-
private static LicenseKey __activatedLicense;
167+
private class __ActivatedLicense
168+
{
169+
internal readonly LicenseKey LicenseKey;
170+
internal __ActivatedLicense(LicenseKey licenseKey) => LicenseKey = licenseKey;
171+
}
172+
173+
private static __ActivatedLicense __activatedLicense;
168174
public static void RegisterLicense(string licenseKeyText)
169175
{
170176
JsConfig.InitStatics();
171177

172-
if (__activatedLicense != null) //Skip multple license registrations. Use RemoveLicense() to reset.
178+
if (__activatedLicense != null) //Skip multiple license registrations. Use RemoveLicense() to reset.
173179
return;
174180

175181
string subId = null;
@@ -183,7 +189,7 @@ public static void RegisterLicense(string licenseKeyText)
183189
if (int.TryParse(subId, out var subIdInt) && revokedSubs.Contains(subIdInt))
184190
throw new LicenseException("This subscription has been revoked. " + ContactDetails);
185191

186-
var key = PclExport.Instance.VerifyLicenseKeyText(licenseKeyText);
192+
var key = VerifyLicenseKeyText(licenseKeyText);
187193
ValidateLicenseKey(key);
188194
}
189195
catch (Exception ex)
@@ -226,7 +232,7 @@ private static void ValidateLicenseKey(LicenseKey key)
226232
if (key.Type == LicenseType.Trial && DateTime.UtcNow > key.Expiry)
227233
throw new LicenseException($"This trial license has expired on {key.Expiry:d}." + ContactDetails).Trace();
228234

229-
__activatedLicense = key;
235+
__activatedLicense = new __ActivatedLicense(key);
230236
}
231237

232238
public static void RemoveLicense()
@@ -236,7 +242,7 @@ public static void RemoveLicense()
236242

237243
public static LicenseFeature ActivatedLicenseFeatures()
238244
{
239-
return __activatedLicense != null ? __activatedLicense.GetLicensedFeatures() : LicenseFeature.None;
245+
return __activatedLicense?.LicenseKey.GetLicensedFeatures() ?? LicenseFeature.None;
240246
}
241247

242248
public static void ApprovedUsage(LicenseFeature licenseFeature, LicenseFeature requestedFeature,
@@ -423,12 +429,192 @@ public static string GetHashKeyToSign(this LicenseKey key)
423429

424430
public static Exception GetInnerMostException(this Exception ex)
425431
{
426-
//Extract true exception from static intializers (e.g. LicenseException)
432+
//Extract true exception from static initializers (e.g. LicenseException)
427433
while (ex.InnerException != null)
428434
{
429435
ex = ex.InnerException;
430436
}
431437
return ex;
432438
}
439+
440+
//License Utils
441+
public static bool VerifySignedHash(byte[] DataToVerify, byte[] SignedData, System.Security.Cryptography.RSAParameters Key)
442+
{
443+
try
444+
{
445+
var RSAalg = new System.Security.Cryptography.RSACryptoServiceProvider();
446+
RSAalg.ImportParameters(Key);
447+
return RSAalg.VerifySha1Data(DataToVerify, SignedData);
448+
449+
}
450+
catch (System.Security.Cryptography.CryptographicException ex)
451+
{
452+
Tracer.Instance.WriteError(ex);
453+
return false;
454+
}
455+
}
456+
457+
public static LicenseKey VerifyLicenseKeyText(string licenseKeyText)
458+
{
459+
#if NET45 || NETCORE2_1
460+
LicenseKey key;
461+
try
462+
{
463+
if (!licenseKeyText.VerifyLicenseKeyText(out key))
464+
throw new ArgumentException("licenseKeyText");
465+
}
466+
catch (Exception e)
467+
{
468+
if (!VerifyLicenseKeyTextFallback(licenseKeyText, out key))
469+
throw;
470+
}
471+
return key;
472+
#else
473+
return licenseKeyText.ToLicenseKey();
474+
#endif
475+
}
476+
477+
private static void FromXml(this System.Security.Cryptography.RSA rsa, string xml)
478+
{
479+
#if NET45
480+
rsa.FromXmlString(xml);
481+
#else
482+
//throws PlatformNotSupportedException
483+
var csp = ExtractFromXml(xml);
484+
rsa.ImportParameters(csp);
485+
#endif
486+
}
487+
488+
#if !NET45
489+
private static System.Security.Cryptography.RSAParameters ExtractFromXml(string xml)
490+
{
491+
var csp = new System.Security.Cryptography.RSAParameters();
492+
using (var reader = System.Xml.XmlReader.Create(new StringReader(xml)))
493+
{
494+
while (reader.Read())
495+
{
496+
if (reader.NodeType != System.Xml.XmlNodeType.Element)
497+
continue;
498+
499+
var elName = reader.Name;
500+
if (elName == "RSAKeyValue")
501+
continue;
502+
503+
do {
504+
reader.Read();
505+
} while (reader.NodeType != System.Xml.XmlNodeType.Text && reader.NodeType != System.Xml.XmlNodeType.EndElement);
506+
507+
if (reader.NodeType == System.Xml.XmlNodeType.EndElement)
508+
continue;
509+
510+
var value = reader.Value;
511+
switch (elName)
512+
{
513+
case "Modulus":
514+
csp.Modulus = Convert.FromBase64String(value);
515+
break;
516+
case "Exponent":
517+
csp.Exponent = Convert.FromBase64String(value);
518+
break;
519+
case "P":
520+
csp.P = Convert.FromBase64String(value);
521+
break;
522+
case "Q":
523+
csp.Q = Convert.FromBase64String(value);
524+
break;
525+
case "DP":
526+
csp.DP = Convert.FromBase64String(value);
527+
break;
528+
case "DQ":
529+
csp.DQ = Convert.FromBase64String(value);
530+
break;
531+
case "InverseQ":
532+
csp.InverseQ = Convert.FromBase64String(value);
533+
break;
534+
case "D":
535+
csp.D = Convert.FromBase64String(value);
536+
break;
537+
}
538+
}
539+
540+
return csp;
541+
}
542+
}
543+
#endif
544+
545+
public static bool VerifyLicenseKeyText(this string licenseKeyText, out LicenseKey key)
546+
{
547+
var publicRsaProvider = new System.Security.Cryptography.RSACryptoServiceProvider();
548+
publicRsaProvider.FromXml(LicenseUtils.LicensePublicKey);
549+
var publicKeyParams = publicRsaProvider.ExportParameters(false);
550+
551+
key = licenseKeyText.ToLicenseKey();
552+
var originalData = key.GetHashKeyToSign().ToUtf8Bytes();
553+
var signedData = Convert.FromBase64String(key.Hash);
554+
555+
return VerifySignedHash(originalData, signedData, publicKeyParams);
556+
}
557+
558+
public static bool VerifyLicenseKeyTextFallback(this string licenseKeyText, out LicenseKey key)
559+
{
560+
System.Security.Cryptography.RSAParameters publicKeyParams;
561+
try
562+
{
563+
var publicRsaProvider = new System.Security.Cryptography.RSACryptoServiceProvider();
564+
publicRsaProvider.FromXml(LicenseUtils.LicensePublicKey);
565+
publicKeyParams = publicRsaProvider.ExportParameters(false);
566+
}
567+
catch (Exception ex)
568+
{
569+
throw new Exception("Could not import LicensePublicKey", ex);
570+
}
571+
572+
try
573+
{
574+
key = licenseKeyText.ToLicenseKeyFallback();
575+
}
576+
catch (Exception ex)
577+
{
578+
throw new Exception("Could not deserialize LicenseKeyText Manually", ex);
579+
}
580+
581+
byte[] originalData;
582+
byte[] signedData;
583+
584+
try
585+
{
586+
originalData = key.GetHashKeyToSign().ToUtf8Bytes();
587+
}
588+
catch (Exception ex)
589+
{
590+
throw new Exception("Could not convert HashKey to UTF-8", ex);
591+
}
592+
593+
try
594+
{
595+
signedData = Convert.FromBase64String(key.Hash);
596+
}
597+
catch (Exception ex)
598+
{
599+
throw new Exception("Could not convert key.Hash from Base64", ex);
600+
}
601+
602+
try
603+
{
604+
return VerifySignedHash(originalData, signedData, publicKeyParams);
605+
}
606+
catch (Exception ex)
607+
{
608+
throw new Exception($"Could not Verify License Key ({originalData.Length}, {signedData.Length})", ex);
609+
}
610+
}
611+
612+
public static bool VerifySha1Data(this System.Security.Cryptography.RSACryptoServiceProvider RSAalg, byte[] unsignedData, byte[] encryptedData)
613+
{
614+
using (var sha = new System.Security.Cryptography.SHA1CryptoServiceProvider())
615+
{
616+
return RSAalg.VerifyData(unsignedData, sha, encryptedData);
617+
}
618+
}
433619
}
434620
}

src/ServiceStack.Text/PclExport.Net45.cs

Lines changed: 1 addition & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -390,8 +390,7 @@ public override void CloseStream(Stream stream)
390390

391391
public override LicenseKey VerifyLicenseKeyText(string licenseKeyText)
392392
{
393-
LicenseKey key;
394-
if (!licenseKeyText.VerifyLicenseKeyText(out key))
393+
if (!licenseKeyText.VerifyLicenseKeyText(out LicenseKey key))
395394
throw new ArgumentException("licenseKeyText");
396395

397396
return key;
@@ -613,98 +612,6 @@ public static byte[] Compress<TXmlDto>(TXmlDto from)
613612
}
614613
}
615614

616-
//License Utils
617-
public static bool VerifySignedHash(byte[] DataToVerify, byte[] SignedData, RSAParameters Key)
618-
{
619-
try
620-
{
621-
var RSAalg = new RSACryptoServiceProvider();
622-
RSAalg.ImportParameters(Key);
623-
return RSAalg.VerifySha1Data(DataToVerify, SignedData);
624-
625-
}
626-
catch (CryptographicException ex)
627-
{
628-
Tracer.Instance.WriteError(ex);
629-
return false;
630-
}
631-
}
632-
633-
public static bool VerifyLicenseKeyText(this string licenseKeyText, out LicenseKey key)
634-
{
635-
var publicRsaProvider = new RSACryptoServiceProvider();
636-
publicRsaProvider.FromXmlString(LicenseUtils.LicensePublicKey);
637-
var publicKeyParams = publicRsaProvider.ExportParameters(false);
638-
639-
key = licenseKeyText.ToLicenseKey();
640-
var originalData = key.GetHashKeyToSign().ToUtf8Bytes();
641-
var signedData = Convert.FromBase64String(key.Hash);
642-
643-
return VerifySignedHash(originalData, signedData, publicKeyParams);
644-
}
645-
646-
public static bool VerifyLicenseKeyTextFallback(this string licenseKeyText, out LicenseKey key)
647-
{
648-
RSAParameters publicKeyParams;
649-
try
650-
{
651-
var publicRsaProvider = new RSACryptoServiceProvider();
652-
publicRsaProvider.FromXmlString(LicenseUtils.LicensePublicKey);
653-
publicKeyParams = publicRsaProvider.ExportParameters(false);
654-
}
655-
catch (Exception ex)
656-
{
657-
throw new Exception("Could not import LicensePublicKey", ex);
658-
}
659-
660-
try
661-
{
662-
key = licenseKeyText.ToLicenseKeyFallback();
663-
}
664-
catch (Exception ex)
665-
{
666-
throw new Exception("Could not deserialize LicenseKeyText Manually", ex);
667-
}
668-
669-
byte[] originalData;
670-
byte[] signedData;
671-
672-
try
673-
{
674-
originalData = key.GetHashKeyToSign().ToUtf8Bytes();
675-
}
676-
catch (Exception ex)
677-
{
678-
throw new Exception("Could not convert HashKey to UTF-8", ex);
679-
}
680-
681-
try
682-
{
683-
signedData = Convert.FromBase64String(key.Hash);
684-
}
685-
catch (Exception ex)
686-
{
687-
throw new Exception("Could not convert key.Hash from Base64", ex);
688-
}
689-
690-
try
691-
{
692-
return VerifySignedHash(originalData, signedData, publicKeyParams);
693-
}
694-
catch (Exception ex)
695-
{
696-
throw new Exception($"Could not Verify License Key ({originalData.Length}, {signedData.Length})", ex);
697-
}
698-
}
699-
700-
public static bool VerifySha1Data(this RSACryptoServiceProvider RSAalg, byte[] unsignedData, byte[] encryptedData)
701-
{
702-
using (var sha = new SHA1CryptoServiceProvider())
703-
{
704-
return RSAalg.VerifyData(unsignedData, sha, encryptedData);
705-
}
706-
}
707-
708615
//ReflectionExtensions
709616
const string DataContract = "DataContractAttribute";
710617

0 commit comments

Comments
 (0)