certificate.spec.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. /*
  2. * Copyright 2018 Scytl Secure Electronic Voting SA
  3. *
  4. * All rights reserved
  5. *
  6. * See our extended copyright notice in *file 'Copyright.txt' which is part of this source code package
  7. */
  8. /* jshint node:true */
  9. 'use strict';
  10. var certificate = require('../lib/index');
  11. var constants = require('../lib/constants');
  12. var forge = require('node-forge');
  13. var BigInteger = forge.jsbn.BigInteger;
  14. describe('The certificate module should be able to ...', function() {
  15. var EPOCH_TIME_LENGTH = 10;
  16. var rootCertificatePem_ =
  17. '-----BEGIN CERTIFICATE-----MIIEKjCCAxKgAwIBAgIQQtWFdPN4NAvUIWyyJyUlbTANBgkqhkiG9w0BAQsFADBUMRAwDgYDVQQDDAdSb290IENOMRYwFAYDVQQLDA1Sb290IE9yZyBVbml0MREwDwYDVQQKDAhSb290IE9yZzEVMBMGA1UEBhMMUm9vdCBDb3VudHJ5MB4XDTE0MDYxODEwMjMyOFoXDTE1MDYxODEwMjMyOFowVDEQMA4GA1UEAwwHUm9vdCBDTjEWMBQGA1UECwwNUm9vdCBPcmcgVW5pdDERMA8GA1UECgwIUm9vdCBPcmcxFTATBgNVBAYTDFJvb3QgQ291bnRyeTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ4AidkWId1zr4IZgItjE9uv38eB8fIGJGEts2n/XNh/EJ7NYZyBzvKSJR83v7LVJjc4pup5crWyS0B5lQ7uuD3/XZ9QpQFtnGiqlKOKH45zsw3ekaHEAco07L2dZznBuQTGLTlhrmvkCFRa8b8WYC+k90oUPvSd/9S4kA1Jlo9JDKHLer0SbjZCcVRXoLSBKmGWE0xSNfmNuZNONDRbtHvSA8A10AOtxKii9w464MXYzmPil7uM1Og1HC+FXCmkzLNfqQ31Om0jra3nLmrCpBJjRPX7svVnoxajRqpazVQnmJjjpzV7yNLwnR9W8OPwqanXcbxmTkrXMxfLxiVXDFUCAwEAAaOB9zCB9DAPBgNVHRMBAf8EBTADAQH/MDUGCCsGAQUFBwEBAQH/BCYwJDAiBggrBgEFBQcwAYYWaHR0cDovL29jc3AudGhhd3RlLmNvbTA0BgNVHR8BAf8EKjAoMCagJKAihiBodHRwOi8vY3JsLnZlcmlzaWduLmNvbS9wY2EzLmNybDArBgNVHREBAf8EITAfpB0wGzEZMBcGA1UEAwwQUHJpdmF0ZUxhYmVsMy0xNTAOBgNVHQ8BAf8EBAMCAQYwNwYDVR0lAQH/BC0wKwYIKwYBBQUHAwEGCCsGAQUFBwMCBgpghkgBhvhFAQgBBglghkgBhvhCBAEwDQYJKoZIhvcNAQELBQADggEBADmtmjApZAXIkGLaZCdkRnhel53BtEdQnG990Oo/tBBboqy2ipum9ByTj3hNWJB3zuPN77rkrek9rbookNcCgVWhHtTk1lUpUK6ZohDsZh8k0MqIhkz+X+HiWGRsEOptjsCaknyWcWb4aXAevMAQMPm/ktkpQ8AOxAq+gtieewWQZP3kGPhBBCfn8TGjdrn9+ymf8EIbAUFXQ8m+oWeNlrdWhqzRXwQbj4EDds1kZdTo0nCYUdH+XEBF9nMyhAxSQWzCKQQTRFWv1dr3dKapzfgrdH8wEgvptiBYCY62O5+3DxiNK/VWquHz6S5GqIwkmSPDPMUU/qK3SNG3xIL1U1k=-----END CERTIFICATE-----';
  18. var rootRsaPublicKeyPem_ =
  19. '-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAngCJ2RYh3XOvghmAi2MT26/fx4Hx8gYkYS2zaf9c2H8Qns1hnIHO8pIlHze/stUmNzim6nlytbJLQHmVDu64Pf9dn1ClAW2caKqUo4ofjnOzDd6RocQByjTsvZ1nOcG5BMYtOWGua+QIVFrxvxZgL6T3ShQ+9J3/1LiQDUmWj0kMoct6vRJuNkJxVFegtIEqYZYTTFI1+Y25k040NFu0e9IDwDXQA63EqKL3DjrgxdjOY+KXu4zU6DUcL4VcKaTMs1+pDfU6bSOtrecuasKkEmNE9fuy9WejFqNGqlrNVCeYmOOnNXvI0vCdH1bw4/CpqddxvGZOStczF8vGJVcMVQIDAQAB-----END PUBLIC KEY-----';
  20. var rootSerialNumber_ = '88837713778966677489555326888277517677';
  21. var rootNotBefore_ = '1403087008';
  22. var rootNotAfter_ = '1434623008';
  23. var rootCn_ = 'Root CN';
  24. var rootOrgUnit_ = 'Root Org Unit';
  25. var rootOrg_ = 'Root Org';
  26. var rootCountry_ = 'Root Country';
  27. var leafCertificatePem_ =
  28. '-----BEGIN CERTIFICATE-----MIIEMzCCAxugAwIBAgIQRbaPaToIM+VS/d6etgYZ4jANBgkqhkiG9w0BAQsFADBUMRAwDgYDVQQDDAdSb290IENOMRYwFAYDVQQLDA1Sb290IE9yZyBVbml0MREwDwYDVQQKDAhSb290IE9yZzEVMBMGA1UEBhMMUm9vdCBDb3VudHJ5MB4XDTE0MDYxODEwMjMyOFoXDTE1MDYxODEwMjMyOFowYDETMBEGA1UEAwwKU3ViamVjdCBDTjEZMBcGA1UECwwQU3ViamVjdCBPcmcgVW5pdDEUMBIGA1UECgwLU3ViamVjdCBPcmcxGDAWBgNVBAYTD1N1YmplY3QgQ291bnRyeTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAIJcqWVOOW539qKZ0SPmOdVaqLgabw0998SAfzrW8Cs8FaYvia4wRbX5N97RPbf3UkbO/QiveB0YQlnDoi2tqlj643mfUgYhMknK4SL0WVQReNcwYMEDbkbyQrCpgKpWWhTSQ2cRD+K3qZpQZ9Qn1RZn615jiqsD+Re5fWbbnL3kc7H5hdclTxZFvEzLgd2KjIsspsqh5UvLowrLuSPLaYD28LsXTDmPeHzYUl62JGPCLl9YNc3av2dY5bjmkf1KiuFKZ27iWh/xdFYAzYloenEw9AxRhJNG+9IucFOENy/0ul2UEb0rgA6Am4cASrhS+aVuZ/OuaC1W+Ut8LlXVmhsCAwEAAaOB9DCB8TAMBgNVHRMBAf8EAjAAMDUGCCsGAQUFBwEBAQH/BCYwJDAiBggrBgEFBQcwAYYWaHR0cDovL29jc3AudGhhd3RlLmNvbTA0BgNVHR8BAf8EKjAoMCagJKAihiBodHRwOi8vY3JsLnZlcmlzaWduLmNvbS9wY2EzLmNybDArBgNVHREBAf8EITAfpB0wGzEZMBcGA1UEAwwQUHJpdmF0ZUxhYmVsMy0xNTAOBgNVHQ8BAf8EBAMCBsAwNwYDVR0lAQH/BC0wKwYIKwYBBQUHAwEGCCsGAQUFBwMCBgpghkgBhvhFAQgBBglghkgBhvhCBAEwDQYJKoZIhvcNAQELBQADggEBAAWZDJD6bg4ohHewszrAbL2tdUNxhrwCgNaHUhwNK43kiLGH0U9innhL1i0jP1VHNkL1G/+ZCo1qzh/Usji/jtlurfAWtrXku6VRF9NP+itKOY5jJ91Ijkc7t4dgoeJq6iMHn6JbDKIQ88r/Ikd0GdF04o5Qjqq1HlUVmqyIOHeHFla4i4tOxTyUBj34eE1No/xmaKYV1QtR1dqSHblR7OagEo7Dd3fXp7iSrKrXaN0Ef/6zeF3zjU5SMKcUcU9d3CbhS/CrGb+UGlqTXgzPXQWESH9AqBNl67+HF3mYktDQOZYPT5WRO5IKSko2cy9pP9UCsLk4oU3xyOxacWDpk1k=-----END CERTIFICATE-----';
  29. var leafRsaPublicKeyPem_ =
  30. '-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAglypZU45bnf2opnRI+Y51VqouBpvDT33xIB/OtbwKzwVpi+JrjBFtfk33tE9t/dSRs79CK94HRhCWcOiLa2qWPrjeZ9SBiEyScrhIvRZVBF41zBgwQNuRvJCsKmAqlZaFNJDZxEP4repmlBn1CfVFmfrXmOKqwP5F7l9ZtucveRzsfmF1yVPFkW8TMuB3YqMiyymyqHlS8ujCsu5I8tpgPbwuxdMOY94fNhSXrYkY8IuX1g1zdq/Z1jluOaR/UqK4UpnbuJaH/F0VgDNiWh6cTD0DFGEk0b70i5wU4Q3L/S6XZQRvSuADoCbhwBKuFL5pW5n865oLVb5S3wuVdWaGwIDAQAB-----END PUBLIC KEY-----';
  31. var leafSerialNumber_ = '92664638458902967092551440174596626914';
  32. var leafNotBefore_ = '1403087008';
  33. var leafNotAfter_ = '1434623008';
  34. var leafCn_ = 'Subject CN';
  35. var leafOrgUnit_ = 'Subject Org Unit';
  36. var leafOrg_ = 'Subject Org';
  37. var leafCountry_ = 'Subject Country';
  38. var certificateService_;
  39. beforeAll(function() {
  40. certificateService_ = certificate.newService();
  41. });
  42. describe('create a certificate service that should be able to ..', function() {
  43. it('load a root X.509 certificate into a new X509Certificate object and retrieve its contents',
  44. function() {
  45. // Load root certificate object.
  46. var rootCertificate =
  47. certificateService_.newX509Certificate(rootCertificatePem_);
  48. // Check that expected fields can be retrieved from root certificate.
  49. expect(new BigInteger(rootCertificate.serialNumber, 16))
  50. .toEqual(new BigInteger(rootSerialNumber_));
  51. var notBefore =
  52. rootCertificate.notBefore.getTime().toString().substring(
  53. 0, EPOCH_TIME_LENGTH);
  54. expect(notBefore).toBe(rootNotBefore_);
  55. var notAfter = rootCertificate.notAfter.getTime().toString().substring(
  56. 0, EPOCH_TIME_LENGTH);
  57. expect(notAfter).toBe(rootNotAfter_);
  58. expect(rootCertificate.subjectCommonName).toBe(rootCn_);
  59. expect(rootCertificate.subjectOrganizationalUnit).toBe(rootOrgUnit_);
  60. expect(rootCertificate.subjectOrganization).toBe(rootOrg_);
  61. expect(rootCertificate.subjectCountry).toBe(rootCountry_);
  62. expect(rootCertificate.issuerCommonName).toBe(rootCn_);
  63. expect(rootCertificate.issuerOrganizationalUnit).toBe(rootOrgUnit_);
  64. expect(rootCertificate.issuerOrganization).toBe(rootOrg_);
  65. expect(rootCertificate.issuerCountry).toBe(rootCountry_);
  66. // Check that public key retrieved from root certificate is same as
  67. // original.
  68. var rootPublicKeyPem = removeNewLineChars(rootCertificate.publicKey);
  69. expect(rootPublicKeyPem).toBe(rootRsaPublicKeyPem_);
  70. var rootPublicKey = forge.pki.publicKeyFromPem(rootPublicKeyPem);
  71. var rootPublicKeyOrig =
  72. forge.pki.publicKeyFromPem(rootRsaPublicKeyPem_);
  73. expect(rootPublicKey.e).toEqual(rootPublicKeyOrig.e);
  74. expect(rootPublicKey.n).toEqual(rootPublicKeyOrig.n);
  75. // Check that expected basic constraints flags can be retrieved from
  76. // certificate.
  77. var basicConstraints = rootCertificate.basicConstraints;
  78. expect((basicConstraints.ca)).toBe(true);
  79. // Check that expected key usage flags can be retrieved from
  80. // certificate.
  81. var keyUsageExtension = rootCertificate.keyUsageExtension;
  82. expect(keyUsageExtension.digitalSignature).toBe(false);
  83. expect(keyUsageExtension.nonRepudiation).toBe(false);
  84. expect(keyUsageExtension.keyEncipherment).toBe(false);
  85. expect(keyUsageExtension.dataEncipherment).toBe(false);
  86. expect(keyUsageExtension.keyAgreement).toBe(false);
  87. expect(keyUsageExtension.keyCertSign).toBe(true);
  88. expect(keyUsageExtension.crlSign).toBe(true);
  89. expect(keyUsageExtension.encipherOnly).toBe(false);
  90. expect(keyUsageExtension.decipherOnly).toBe(false);
  91. // Check that root certificate is self-signed.
  92. expect(rootCertificate.verify(rootCertificatePem_)).toBe(true);
  93. // Serialize root certificate to PEM format.
  94. var rootCertificatePem = rootCertificate.toPem();
  95. var offset = rootCertificatePem.indexOf('\n') + 1;
  96. expect(rootCertificatePem.indexOf('\n', offset))
  97. .toBe(offset + constants.PEM_LINE_LENGTH + 1);
  98. expect(removeNewLineChars(rootCertificatePem))
  99. .toBe(rootCertificatePem_);
  100. });
  101. it('load a leaf X.509 certificate into a new X509Certificate object and retrieve its contents',
  102. function() {
  103. // Load leaf certificate.
  104. var leafCertificate =
  105. certificateService_.newX509Certificate(leafCertificatePem_);
  106. // Check that expected fields can be retrieved from leaf certificate.
  107. expect(new BigInteger(leafCertificate.serialNumber, 16))
  108. .toEqual(new forge.jsbn.BigInteger(leafSerialNumber_));
  109. var notBefore =
  110. leafCertificate.notBefore.getTime().toString().substring(
  111. 0, EPOCH_TIME_LENGTH);
  112. expect(notBefore).toBe(leafNotBefore_);
  113. var notAfter = leafCertificate.notAfter.getTime().toString().substring(
  114. 0, EPOCH_TIME_LENGTH);
  115. expect(notAfter).toBe(leafNotAfter_);
  116. expect(leafCertificate.subjectCommonName).toBe(leafCn_);
  117. expect(leafCertificate.subjectOrganizationalUnit).toBe(leafOrgUnit_);
  118. expect(leafCertificate.subjectOrganization).toBe(leafOrg_);
  119. expect(leafCertificate.subjectCountry).toBe(leafCountry_);
  120. expect(leafCertificate.issuerCommonName).toBe(rootCn_);
  121. expect(leafCertificate.issuerOrganizationalUnit).toBe(rootOrgUnit_);
  122. expect(leafCertificate.issuerOrganization).toBe(rootOrg_);
  123. expect(leafCertificate.issuerCountry).toBe(rootCountry_);
  124. // Check that public key retrieved from certificate is same as
  125. // original.
  126. var leafPublicKeyPem = removeNewLineChars(leafCertificate.publicKey);
  127. expect(leafPublicKeyPem).toBe(leafRsaPublicKeyPem_);
  128. var leafPublicKey = forge.pki.publicKeyFromPem(leafPublicKeyPem);
  129. var leafPublicKeyOrig =
  130. forge.pki.publicKeyFromPem(leafRsaPublicKeyPem_);
  131. expect(leafPublicKey.e).toEqual(leafPublicKeyOrig.e);
  132. expect(leafPublicKey.n).toEqual(leafPublicKeyOrig.n);
  133. // Check that expected basic constraints flags can be retrieved from
  134. // certificate.
  135. var basicConstraints = leafCertificate.basicConstraints;
  136. expect((basicConstraints.ca)).toBe(false);
  137. // Check that expected key usage flags can be retrieved from
  138. // certificate.
  139. var keyUsageExtension = leafCertificate.keyUsageExtension;
  140. expect(keyUsageExtension.digitalSignature).toBe(true);
  141. expect(keyUsageExtension.nonRepudiation).toBe(true);
  142. expect(keyUsageExtension.keyEncipherment).toBe(false);
  143. expect(keyUsageExtension.dataEncipherment).toBe(false);
  144. expect(keyUsageExtension.keyAgreement).toBe(false);
  145. expect(keyUsageExtension.keyCertSign).toBe(false);
  146. expect(keyUsageExtension.crlSign).toBe(false);
  147. expect(keyUsageExtension.encipherOnly).toBe(false);
  148. expect(keyUsageExtension.decipherOnly).toBe(false);
  149. // Verify that leaf certificate was signed by root certificate.
  150. var rootCertificate =
  151. certificateService_.newX509Certificate(rootCertificatePem_);
  152. expect(rootCertificate.verify(leafCertificatePem_)).toBe(true);
  153. // Serialize leaf certificate to PEM format.
  154. var leafCertificatePem = leafCertificate.toPem();
  155. var offset = leafCertificatePem.indexOf('\n') + 1;
  156. expect(leafCertificatePem.indexOf('\n', offset))
  157. .toBe(offset + constants.PEM_LINE_LENGTH + 1);
  158. expect(removeNewLineChars(leafCertificatePem))
  159. .toBe(leafCertificatePem_);
  160. });
  161. });
  162. function removeNewLineChars(str) {
  163. return str.replace(/(\r\n|\n|\r)/gm, '');
  164. }
  165. });