Sin descripción
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Certificate.cs 9.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using LipingShare.LCLib.Asn1Processor;
  5. using System.Security.Cryptography;
  6. namespace UnityEngine.Purchasing.Security
  7. {
  8. internal class DistinguishedName
  9. {
  10. public string Country { get; set; }
  11. public string Organization { get; set; }
  12. public string OrganizationalUnit { get; set; }
  13. public string Dnq { get; set; }
  14. public string State { get; set; }
  15. public string CommonName { get; set; }
  16. public string SerialNumber { get; set; }
  17. public DistinguishedName(Asn1Node n)
  18. {
  19. /* Name:
  20. * SET
  21. * SEQ (attr)
  22. * Object Identifier
  23. * Printable String || UTF8String
  24. */
  25. if (n.MaskedTag == Asn1Tag.SEQUENCE)
  26. {
  27. for (int i = 0; i < n.ChildNodeCount; i++)
  28. {
  29. Asn1Node tt = n.GetChildNode(i);
  30. if (tt.MaskedTag != Asn1Tag.SET || tt.ChildNodeCount != 1)
  31. throw new InvalidX509Data();
  32. tt = tt.GetChildNode(0);
  33. if (tt.MaskedTag != Asn1Tag.SEQUENCE || tt.ChildNodeCount != 2)
  34. throw new InvalidX509Data();
  35. Asn1Node oi = tt.GetChildNode(0);
  36. Asn1Node txt = tt.GetChildNode(1);
  37. if (oi.MaskedTag != Asn1Tag.OBJECT_IDENTIFIER ||
  38. !(
  39. (txt.MaskedTag == Asn1Tag.PRINTABLE_STRING) ||
  40. (txt.MaskedTag == Asn1Tag.UTF8_STRING) ||
  41. (txt.MaskedTag == Asn1Tag.IA5_STRING)))
  42. {
  43. throw new InvalidX509Data();
  44. }
  45. var xoid = new LipingShare.LCLib.Asn1Processor.Oid();
  46. string oiName = xoid.Decode(oi.Data);
  47. var enc = new System.Text.UTF8Encoding();
  48. switch (oiName)
  49. {
  50. case "2.5.4.6": // countryName
  51. Country = enc.GetString(txt.Data);
  52. break;
  53. case "2.5.4.10": // organizationName
  54. Organization = enc.GetString(txt.Data);
  55. break;
  56. case "2.5.4.11": // organizationalUnit
  57. OrganizationalUnit = enc.GetString(txt.Data);
  58. break;
  59. case "2.5.4.3": // commonName
  60. CommonName = enc.GetString(txt.Data);
  61. break;
  62. case "2.5.4.5": // serial number
  63. SerialNumber = Asn1Util.ToHexString(txt.Data);
  64. break;
  65. case "2.5.4.46": // dnq
  66. Dnq = enc.GetString(txt.Data);
  67. break;
  68. case "2.5.4.8": // state
  69. State = enc.GetString(txt.Data);
  70. break;
  71. }
  72. }
  73. }
  74. }
  75. public bool Equals(DistinguishedName n2)
  76. {
  77. return this.Organization == n2.Organization &&
  78. this.OrganizationalUnit == n2.OrganizationalUnit &&
  79. this.Dnq == n2.Dnq &&
  80. this.Country == n2.Country &&
  81. this.State == n2.State &&
  82. this.CommonName == n2.CommonName;
  83. }
  84. public override string ToString()
  85. {
  86. return "CN: " + CommonName + "\n" +
  87. "ON: " + Organization + "\n" +
  88. "Unit Name: " + OrganizationalUnit + "\n" +
  89. "Country: " + Country;
  90. }
  91. }
  92. internal class X509Cert
  93. {
  94. public string SerialNumber { get; private set; }
  95. public DateTime ValidAfter { get; private set; }
  96. public DateTime ValidBefore { get; private set; }
  97. public RSAKey PubKey { get; private set; }
  98. public bool SelfSigned { get; private set; }
  99. public DistinguishedName Subject { get; private set; }
  100. public DistinguishedName Issuer { get; private set; }
  101. private Asn1Node TbsCertificate;
  102. public Asn1Node Signature { get; private set; }
  103. public byte[] rawTBSCertificate;
  104. public X509Cert(Asn1Node n)
  105. {
  106. ParseNode(n);
  107. }
  108. public X509Cert(byte[] data)
  109. {
  110. using (var stm = new System.IO.MemoryStream(data))
  111. {
  112. Asn1Parser parser = new Asn1Parser();
  113. parser.LoadData(stm);
  114. ParseNode(parser.RootNode);
  115. }
  116. }
  117. public bool CheckCertTime(DateTime time)
  118. {
  119. return time.CompareTo(ValidAfter) >= 0 && time.CompareTo(ValidBefore) <= 0;
  120. }
  121. public bool CheckSignature(X509Cert signer)
  122. {
  123. if (Issuer.Equals(signer.Subject))
  124. {
  125. return VerifySignatureWithSha256OrSha1(signer);
  126. }
  127. return false;
  128. }
  129. bool VerifySignatureWithSha256OrSha1(X509Cert signer)
  130. {
  131. if (signer.PubKey.VerifySha256(rawTBSCertificate, Signature.Data))
  132. {
  133. return true;
  134. }
  135. return signer.PubKey.VerifySha1(rawTBSCertificate, Signature.Data);
  136. }
  137. public bool CheckSignatureSha256(X509Cert signer)
  138. {
  139. if (Issuer.Equals(signer.Subject))
  140. {
  141. return signer.PubKey.VerifySha256(rawTBSCertificate, Signature.Data);
  142. }
  143. return false;
  144. }
  145. private void ParseNode(Asn1Node root)
  146. {
  147. if ((root.Tag & Asn1Tag.TAG_MASK) != Asn1Tag.SEQUENCE || root.ChildNodeCount != 3)
  148. throw new InvalidX509Data();
  149. // TBS cert
  150. TbsCertificate = root.GetChildNode(0);
  151. if (TbsCertificate.ChildNodeCount < 7)
  152. throw new InvalidX509Data();
  153. rawTBSCertificate = new byte[TbsCertificate.DataLength + 4];
  154. Array.Copy(root.Data, 0, rawTBSCertificate, 0, rawTBSCertificate.Length);
  155. // get the serial number
  156. Asn1Node sn = TbsCertificate.GetChildNode(1);
  157. if ((sn.Tag & Asn1Tag.TAG_MASK) != Asn1Tag.INTEGER)
  158. throw new InvalidX509Data();
  159. SerialNumber = Asn1Util.ToHexString(sn.Data);
  160. // get the issuer
  161. Issuer = new DistinguishedName(TbsCertificate.GetChildNode(3));
  162. // get the subject
  163. Subject = new DistinguishedName(TbsCertificate.GetChildNode(5));
  164. // get the dates
  165. Asn1Node validTimes = TbsCertificate.GetChildNode(4);
  166. if ((validTimes.Tag & Asn1Tag.TAG_MASK) != Asn1Tag.SEQUENCE || validTimes.ChildNodeCount != 2)
  167. throw new InvalidX509Data();
  168. ValidAfter = ParseTime(validTimes.GetChildNode(0));
  169. ValidBefore = ParseTime(validTimes.GetChildNode(1));
  170. // is this self signed?
  171. SelfSigned = Subject.Equals(Issuer);
  172. // get the pub key
  173. PubKey = new RSAKey(TbsCertificate.GetChildNode(6));
  174. // set the tbs cert & signature data for signature verification
  175. Signature = root.GetChildNode(2);
  176. }
  177. /**
  178. * According to rfc5280, time should be specified in GMT:
  179. * https://tools.ietf.org/html/rfc5280#section-4.1.2.5
  180. */
  181. private DateTime ParseTime(Asn1Node n)
  182. {
  183. string time = (new System.Text.UTF8Encoding()).GetString(n.Data);
  184. if (!(time.Length == 13 || time.Length == 15))
  185. throw new InvalidTimeFormat();
  186. // only accept Zulu time
  187. if (time[time.Length - 1] != 'Z')
  188. throw new InvalidTimeFormat();
  189. int curIdx = 0;
  190. int year = 0;
  191. if (time.Length == 13)
  192. {
  193. year = Int32.Parse(time.Substring(0, 2));
  194. if (year >= 50)
  195. year += 1900;
  196. else if (year < 50)
  197. year += 2000;
  198. curIdx += 2;
  199. }
  200. else
  201. {
  202. year = Int32.Parse(time.Substring(0, 4));
  203. curIdx += 4;
  204. }
  205. int month = Int32.Parse(time.Substring(curIdx, 2)); curIdx += 2;
  206. int dom = Int32.Parse(time.Substring(curIdx, 2)); curIdx += 2;
  207. int hour = Int32.Parse(time.Substring(curIdx, 2)); curIdx += 2;
  208. int min = Int32.Parse(time.Substring(curIdx, 2)); curIdx += 2;
  209. int secs = Int32.Parse(time.Substring(curIdx, 2)); curIdx += 2;
  210. return new DateTime(year, month, dom, hour, min, secs, DateTimeKind.Utc);
  211. }
  212. }
  213. /// <summary>
  214. /// An IAP Security exception indicating some invalid time format.
  215. /// </summary>
  216. public class InvalidTimeFormat : IAPSecurityException { }
  217. /// <summary>
  218. /// An IAP Security exception indicating some invalid data for X509 certification checks.
  219. /// </summary>
  220. public class InvalidX509Data : IAPSecurityException { }
  221. }