ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
X509.php
Go to the documentation of this file.
1 <?php
2 
27 namespace phpseclib\File;
28 
35 
43 class X509
44 {
53 
61  const DN_ARRAY = 0;
65  const DN_STRING = 1;
69  const DN_ASN1 = 2;
73  const DN_OPENSSL = 3;
77  const DN_CANON = 4;
81  const DN_HASH = 5;
95  const FORMAT_PEM = 0;
99  const FORMAT_DER = 1;
105  const FORMAT_SPKAC = 2;
118  const ATTR_ALL = -1; // All attribute values (array).
119  const ATTR_APPEND = -2; // Add a value.
120  const ATTR_REPLACE = -3; // Clear first, then add a value.
121 
129 
152 
153  var $CPSuri;
155 
159 
160  var $Name;
178 
186 
193  var $dn;
194 
202 
210 
218  var $oids;
219 
226  var $CAs;
227 
235 
246 
254 
261  var $endDate;
262 
270 
281 
288  var $caFlag = false;
289 
297 
304  function __construct()
305  {
306  // Explicitly Tagged Module, 1988 Syntax
307  // http://tools.ietf.org/html/rfc5280#appendix-A.1
308 
309  $this->DirectoryString = array(
310  'type' => ASN1::TYPE_CHOICE,
311  'children' => array(
312  'teletexString' => array('type' => ASN1::TYPE_TELETEX_STRING),
313  'printableString' => array('type' => ASN1::TYPE_PRINTABLE_STRING),
314  'universalString' => array('type' => ASN1::TYPE_UNIVERSAL_STRING),
315  'utf8String' => array('type' => ASN1::TYPE_UTF8_STRING),
316  'bmpString' => array('type' => ASN1::TYPE_BMP_STRING)
317  )
318  );
319 
320  $this->PKCS9String = array(
321  'type' => ASN1::TYPE_CHOICE,
322  'children' => array(
323  'ia5String' => array('type' => ASN1::TYPE_IA5_STRING),
324  'directoryString' => $this->DirectoryString
325  )
326  );
327 
328  $this->AttributeValue = array('type' => ASN1::TYPE_ANY);
329 
330  $AttributeType = array('type' => ASN1::TYPE_OBJECT_IDENTIFIER);
331 
332  $AttributeTypeAndValue = array(
333  'type' => ASN1::TYPE_SEQUENCE,
334  'children' => array(
335  'type' => $AttributeType,
336  'value'=> $this->AttributeValue
337  )
338  );
339 
340  /*
341  In practice, RDNs containing multiple name-value pairs (called "multivalued RDNs") are rare,
342  but they can be useful at times when either there is no unique attribute in the entry or you
343  want to ensure that the entry's DN contains some useful identifying information.
344 
345  - https://www.opends.org/wiki/page/DefinitionRelativeDistinguishedName
346  */
347  $this->RelativeDistinguishedName = array(
348  'type' => ASN1::TYPE_SET,
349  'min' => 1,
350  'max' => -1,
351  'children' => $AttributeTypeAndValue
352  );
353 
354  // http://tools.ietf.org/html/rfc5280#section-4.1.2.4
355  $RDNSequence = array(
356  'type' => ASN1::TYPE_SEQUENCE,
357  // RDNSequence does not define a min or a max, which means it doesn't have one
358  'min' => 0,
359  'max' => -1,
360  'children' => $this->RelativeDistinguishedName
361  );
362 
363  $this->Name = array(
364  'type' => ASN1::TYPE_CHOICE,
365  'children' => array(
366  'rdnSequence' => $RDNSequence
367  )
368  );
369 
370  // http://tools.ietf.org/html/rfc5280#section-4.1.1.2
371  $AlgorithmIdentifier = array(
372  'type' => ASN1::TYPE_SEQUENCE,
373  'children' => array(
374  'algorithm' => array('type' => ASN1::TYPE_OBJECT_IDENTIFIER),
375  'parameters' => array(
376  'type' => ASN1::TYPE_ANY,
377  'optional' => true
378  )
379  )
380  );
381 
382  /*
383  A certificate using system MUST reject the certificate if it encounters
384  a critical extension it does not recognize; however, a non-critical
385  extension may be ignored if it is not recognized.
386 
387  http://tools.ietf.org/html/rfc5280#section-4.2
388  */
389  $Extension = array(
390  'type' => ASN1::TYPE_SEQUENCE,
391  'children' => array(
392  'extnId' => array('type' => ASN1::TYPE_OBJECT_IDENTIFIER),
393  'critical' => array(
394  'type' => ASN1::TYPE_BOOLEAN,
395  'optional' => true,
396  'default' => false
397  ),
398  'extnValue' => array('type' => ASN1::TYPE_OCTET_STRING)
399  )
400  );
401 
402  $this->Extensions = array(
403  'type' => ASN1::TYPE_SEQUENCE,
404  'min' => 1,
405  // technically, it's MAX, but we'll assume anything < 0 is MAX
406  'max' => -1,
407  // if 'children' isn't an array then 'min' and 'max' must be defined
408  'children' => $Extension
409  );
410 
411  $SubjectPublicKeyInfo = array(
412  'type' => ASN1::TYPE_SEQUENCE,
413  'children' => array(
414  'algorithm' => $AlgorithmIdentifier,
415  'subjectPublicKey' => array('type' => ASN1::TYPE_BIT_STRING)
416  )
417  );
418 
419  $UniqueIdentifier = array('type' => ASN1::TYPE_BIT_STRING);
420 
421  $Time = array(
422  'type' => ASN1::TYPE_CHOICE,
423  'children' => array(
424  'utcTime' => array('type' => ASN1::TYPE_UTC_TIME),
425  'generalTime' => array('type' => ASN1::TYPE_GENERALIZED_TIME)
426  )
427  );
428 
429  // http://tools.ietf.org/html/rfc5280#section-4.1.2.5
430  $Validity = array(
431  'type' => ASN1::TYPE_SEQUENCE,
432  'children' => array(
433  'notBefore' => $Time,
434  'notAfter' => $Time
435  )
436  );
437 
438  $CertificateSerialNumber = array('type' => ASN1::TYPE_INTEGER);
439 
440  $Version = array(
441  'type' => ASN1::TYPE_INTEGER,
442  'mapping' => array('v1', 'v2', 'v3')
443  );
444 
445  // assert($TBSCertificate['children']['signature'] == $Certificate['children']['signatureAlgorithm'])
446  $TBSCertificate = array(
447  'type' => ASN1::TYPE_SEQUENCE,
448  'children' => array(
449  // technically, default implies optional, but we'll define it as being optional, none-the-less, just to
450  // reenforce that fact
451  'version' => array(
452  'constant' => 0,
453  'optional' => true,
454  'explicit' => true,
455  'default' => 'v1'
456  ) + $Version,
457  'serialNumber' => $CertificateSerialNumber,
458  'signature' => $AlgorithmIdentifier,
459  'issuer' => $this->Name,
460  'validity' => $Validity,
461  'subject' => $this->Name,
462  'subjectPublicKeyInfo' => $SubjectPublicKeyInfo,
463  // implicit means that the T in the TLV structure is to be rewritten, regardless of the type
464  'issuerUniqueID' => array(
465  'constant' => 1,
466  'optional' => true,
467  'implicit' => true
468  ) + $UniqueIdentifier,
469  'subjectUniqueID' => array(
470  'constant' => 2,
471  'optional' => true,
472  'implicit' => true
473  ) + $UniqueIdentifier,
474  // <http://tools.ietf.org/html/rfc2459#page-74> doesn't use the EXPLICIT keyword but if
475  // it's not IMPLICIT, it's EXPLICIT
476  'extensions' => array(
477  'constant' => 3,
478  'optional' => true,
479  'explicit' => true
480  ) + $this->Extensions
481  )
482  );
483 
484  $this->Certificate = array(
485  'type' => ASN1::TYPE_SEQUENCE,
486  'children' => array(
487  'tbsCertificate' => $TBSCertificate,
488  'signatureAlgorithm' => $AlgorithmIdentifier,
489  'signature' => array('type' => ASN1::TYPE_BIT_STRING)
490  )
491  );
492 
493  $this->KeyUsage = array(
494  'type' => ASN1::TYPE_BIT_STRING,
495  'mapping' => array(
496  'digitalSignature',
497  'nonRepudiation',
498  'keyEncipherment',
499  'dataEncipherment',
500  'keyAgreement',
501  'keyCertSign',
502  'cRLSign',
503  'encipherOnly',
504  'decipherOnly'
505  )
506  );
507 
508  $this->BasicConstraints = array(
509  'type' => ASN1::TYPE_SEQUENCE,
510  'children' => array(
511  'cA' => array(
512  'type' => ASN1::TYPE_BOOLEAN,
513  'optional' => true,
514  'default' => false
515  ),
516  'pathLenConstraint' => array(
517  'type' => ASN1::TYPE_INTEGER,
518  'optional' => true
519  )
520  )
521  );
522 
523  $this->KeyIdentifier = array('type' => ASN1::TYPE_OCTET_STRING);
524 
525  $OrganizationalUnitNames = array(
526  'type' => ASN1::TYPE_SEQUENCE,
527  'min' => 1,
528  'max' => 4, // ub-organizational-units
529  'children' => array('type' => ASN1::TYPE_PRINTABLE_STRING)
530  );
531 
532  $PersonalName = array(
533  'type' => ASN1::TYPE_SET,
534  'children' => array(
535  'surname' => array(
536  'type' => ASN1::TYPE_PRINTABLE_STRING,
537  'constant' => 0,
538  'optional' => true,
539  'implicit' => true
540  ),
541  'given-name' => array(
542  'type' => ASN1::TYPE_PRINTABLE_STRING,
543  'constant' => 1,
544  'optional' => true,
545  'implicit' => true
546  ),
547  'initials' => array(
548  'type' => ASN1::TYPE_PRINTABLE_STRING,
549  'constant' => 2,
550  'optional' => true,
551  'implicit' => true
552  ),
553  'generation-qualifier' => array(
554  'type' => ASN1::TYPE_PRINTABLE_STRING,
555  'constant' => 3,
556  'optional' => true,
557  'implicit' => true
558  )
559  )
560  );
561 
562  $NumericUserIdentifier = array('type' => ASN1::TYPE_NUMERIC_STRING);
563 
564  $OrganizationName = array('type' => ASN1::TYPE_PRINTABLE_STRING);
565 
566  $PrivateDomainName = array(
567  'type' => ASN1::TYPE_CHOICE,
568  'children' => array(
569  'numeric' => array('type' => ASN1::TYPE_NUMERIC_STRING),
570  'printable' => array('type' => ASN1::TYPE_PRINTABLE_STRING)
571  )
572  );
573 
574  $TerminalIdentifier = array('type' => ASN1::TYPE_PRINTABLE_STRING);
575 
576  $NetworkAddress = array('type' => ASN1::TYPE_NUMERIC_STRING);
577 
578  $AdministrationDomainName = array(
579  'type' => ASN1::TYPE_CHOICE,
580  // if class isn't present it's assumed to be \phpseclib\File\ASN1::CLASS_UNIVERSAL or
581  // (if constant is present) \phpseclib\File\ASN1::CLASS_CONTEXT_SPECIFIC
582  'class' => ASN1::CLASS_APPLICATION,
583  'cast' => 2,
584  'children' => array(
585  'numeric' => array('type' => ASN1::TYPE_NUMERIC_STRING),
586  'printable' => array('type' => ASN1::TYPE_PRINTABLE_STRING)
587  )
588  );
589 
590  $CountryName = array(
591  'type' => ASN1::TYPE_CHOICE,
592  // if class isn't present it's assumed to be \phpseclib\File\ASN1::CLASS_UNIVERSAL or
593  // (if constant is present) \phpseclib\File\ASN1::CLASS_CONTEXT_SPECIFIC
594  'class' => ASN1::CLASS_APPLICATION,
595  'cast' => 1,
596  'children' => array(
597  'x121-dcc-code' => array('type' => ASN1::TYPE_NUMERIC_STRING),
598  'iso-3166-alpha2-code' => array('type' => ASN1::TYPE_PRINTABLE_STRING)
599  )
600  );
601 
602  $AnotherName = array(
603  'type' => ASN1::TYPE_SEQUENCE,
604  'children' => array(
605  'type-id' => array('type' => ASN1::TYPE_OBJECT_IDENTIFIER),
606  'value' => array(
607  'type' => ASN1::TYPE_ANY,
608  'constant' => 0,
609  'optional' => true,
610  'explicit' => true
611  )
612  )
613  );
614 
615  $ExtensionAttribute = array(
616  'type' => ASN1::TYPE_SEQUENCE,
617  'children' => array(
618  'extension-attribute-type' => array(
619  'type' => ASN1::TYPE_PRINTABLE_STRING,
620  'constant' => 0,
621  'optional' => true,
622  'implicit' => true
623  ),
624  'extension-attribute-value' => array(
625  'type' => ASN1::TYPE_ANY,
626  'constant' => 1,
627  'optional' => true,
628  'explicit' => true
629  )
630  )
631  );
632 
633  $ExtensionAttributes = array(
634  'type' => ASN1::TYPE_SET,
635  'min' => 1,
636  'max' => 256, // ub-extension-attributes
637  'children' => $ExtensionAttribute
638  );
639 
640  $BuiltInDomainDefinedAttribute = array(
641  'type' => ASN1::TYPE_SEQUENCE,
642  'children' => array(
643  'type' => array('type' => ASN1::TYPE_PRINTABLE_STRING),
644  'value' => array('type' => ASN1::TYPE_PRINTABLE_STRING)
645  )
646  );
647 
648  $BuiltInDomainDefinedAttributes = array(
649  'type' => ASN1::TYPE_SEQUENCE,
650  'min' => 1,
651  'max' => 4, // ub-domain-defined-attributes
652  'children' => $BuiltInDomainDefinedAttribute
653  );
654 
655  $BuiltInStandardAttributes = array(
656  'type' => ASN1::TYPE_SEQUENCE,
657  'children' => array(
658  'country-name' => array('optional' => true) + $CountryName,
659  'administration-domain-name' => array('optional' => true) + $AdministrationDomainName,
660  'network-address' => array(
661  'constant' => 0,
662  'optional' => true,
663  'implicit' => true
664  ) + $NetworkAddress,
665  'terminal-identifier' => array(
666  'constant' => 1,
667  'optional' => true,
668  'implicit' => true
669  ) + $TerminalIdentifier,
670  'private-domain-name' => array(
671  'constant' => 2,
672  'optional' => true,
673  'explicit' => true
674  ) + $PrivateDomainName,
675  'organization-name' => array(
676  'constant' => 3,
677  'optional' => true,
678  'implicit' => true
679  ) + $OrganizationName,
680  'numeric-user-identifier' => array(
681  'constant' => 4,
682  'optional' => true,
683  'implicit' => true
684  ) + $NumericUserIdentifier,
685  'personal-name' => array(
686  'constant' => 5,
687  'optional' => true,
688  'implicit' => true
689  ) + $PersonalName,
690  'organizational-unit-names' => array(
691  'constant' => 6,
692  'optional' => true,
693  'implicit' => true
694  ) + $OrganizationalUnitNames
695  )
696  );
697 
698  $ORAddress = array(
699  'type' => ASN1::TYPE_SEQUENCE,
700  'children' => array(
701  'built-in-standard-attributes' => $BuiltInStandardAttributes,
702  'built-in-domain-defined-attributes' => array('optional' => true) + $BuiltInDomainDefinedAttributes,
703  'extension-attributes' => array('optional' => true) + $ExtensionAttributes
704  )
705  );
706 
707  $EDIPartyName = array(
708  'type' => ASN1::TYPE_SEQUENCE,
709  'children' => array(
710  'nameAssigner' => array(
711  'constant' => 0,
712  'optional' => true,
713  'implicit' => true
714  ) + $this->DirectoryString,
715  // partyName is technically required but \phpseclib\File\ASN1 doesn't currently support non-optional constants and
716  // setting it to optional gets the job done in any event.
717  'partyName' => array(
718  'constant' => 1,
719  'optional' => true,
720  'implicit' => true
721  ) + $this->DirectoryString
722  )
723  );
724 
725  $GeneralName = array(
726  'type' => ASN1::TYPE_CHOICE,
727  'children' => array(
728  'otherName' => array(
729  'constant' => 0,
730  'optional' => true,
731  'implicit' => true
732  ) + $AnotherName,
733  'rfc822Name' => array(
734  'type' => ASN1::TYPE_IA5_STRING,
735  'constant' => 1,
736  'optional' => true,
737  'implicit' => true
738  ),
739  'dNSName' => array(
740  'type' => ASN1::TYPE_IA5_STRING,
741  'constant' => 2,
742  'optional' => true,
743  'implicit' => true
744  ),
745  'x400Address' => array(
746  'constant' => 3,
747  'optional' => true,
748  'implicit' => true
749  ) + $ORAddress,
750  'directoryName' => array(
751  'constant' => 4,
752  'optional' => true,
753  'explicit' => true
754  ) + $this->Name,
755  'ediPartyName' => array(
756  'constant' => 5,
757  'optional' => true,
758  'implicit' => true
759  ) + $EDIPartyName,
760  'uniformResourceIdentifier' => array(
761  'type' => ASN1::TYPE_IA5_STRING,
762  'constant' => 6,
763  'optional' => true,
764  'implicit' => true
765  ),
766  'iPAddress' => array(
767  'type' => ASN1::TYPE_OCTET_STRING,
768  'constant' => 7,
769  'optional' => true,
770  'implicit' => true
771  ),
772  'registeredID' => array(
774  'constant' => 8,
775  'optional' => true,
776  'implicit' => true
777  )
778  )
779  );
780 
781  $GeneralNames = array(
782  'type' => ASN1::TYPE_SEQUENCE,
783  'min' => 1,
784  'max' => -1,
785  'children' => $GeneralName
786  );
787 
788  $this->IssuerAltName = $GeneralNames;
789 
790  $ReasonFlags = array(
791  'type' => ASN1::TYPE_BIT_STRING,
792  'mapping' => array(
793  'unused',
794  'keyCompromise',
795  'cACompromise',
796  'affiliationChanged',
797  'superseded',
798  'cessationOfOperation',
799  'certificateHold',
800  'privilegeWithdrawn',
801  'aACompromise'
802  )
803  );
804 
805  $DistributionPointName = array(
806  'type' => ASN1::TYPE_CHOICE,
807  'children' => array(
808  'fullName' => array(
809  'constant' => 0,
810  'optional' => true,
811  'implicit' => true
812  ) + $GeneralNames,
813  'nameRelativeToCRLIssuer' => array(
814  'constant' => 1,
815  'optional' => true,
816  'implicit' => true
817  ) + $this->RelativeDistinguishedName
818  )
819  );
820 
821  $DistributionPoint = array(
822  'type' => ASN1::TYPE_SEQUENCE,
823  'children' => array(
824  'distributionPoint' => array(
825  'constant' => 0,
826  'optional' => true,
827  'explicit' => true
828  ) + $DistributionPointName,
829  'reasons' => array(
830  'constant' => 1,
831  'optional' => true,
832  'implicit' => true
833  ) + $ReasonFlags,
834  'cRLIssuer' => array(
835  'constant' => 2,
836  'optional' => true,
837  'implicit' => true
838  ) + $GeneralNames
839  )
840  );
841 
842  $this->CRLDistributionPoints = array(
843  'type' => ASN1::TYPE_SEQUENCE,
844  'min' => 1,
845  'max' => -1,
846  'children' => $DistributionPoint
847  );
848 
849  $this->AuthorityKeyIdentifier = array(
850  'type' => ASN1::TYPE_SEQUENCE,
851  'children' => array(
852  'keyIdentifier' => array(
853  'constant' => 0,
854  'optional' => true,
855  'implicit' => true
856  ) + $this->KeyIdentifier,
857  'authorityCertIssuer' => array(
858  'constant' => 1,
859  'optional' => true,
860  'implicit' => true
861  ) + $GeneralNames,
862  'authorityCertSerialNumber' => array(
863  'constant' => 2,
864  'optional' => true,
865  'implicit' => true
866  ) + $CertificateSerialNumber
867  )
868  );
869 
870  $PolicyQualifierId = array('type' => ASN1::TYPE_OBJECT_IDENTIFIER);
871 
872  $PolicyQualifierInfo = array(
873  'type' => ASN1::TYPE_SEQUENCE,
874  'children' => array(
875  'policyQualifierId' => $PolicyQualifierId,
876  'qualifier' => array('type' => ASN1::TYPE_ANY)
877  )
878  );
879 
880  $CertPolicyId = array('type' => ASN1::TYPE_OBJECT_IDENTIFIER);
881 
882  $PolicyInformation = array(
883  'type' => ASN1::TYPE_SEQUENCE,
884  'children' => array(
885  'policyIdentifier' => $CertPolicyId,
886  'policyQualifiers' => array(
887  'type' => ASN1::TYPE_SEQUENCE,
888  'min' => 0,
889  'max' => -1,
890  'optional' => true,
891  'children' => $PolicyQualifierInfo
892  )
893  )
894  );
895 
896  $this->CertificatePolicies = array(
897  'type' => ASN1::TYPE_SEQUENCE,
898  'min' => 1,
899  'max' => -1,
900  'children' => $PolicyInformation
901  );
902 
903  $this->PolicyMappings = array(
904  'type' => ASN1::TYPE_SEQUENCE,
905  'min' => 1,
906  'max' => -1,
907  'children' => array(
908  'type' => ASN1::TYPE_SEQUENCE,
909  'children' => array(
910  'issuerDomainPolicy' => $CertPolicyId,
911  'subjectDomainPolicy' => $CertPolicyId
912  )
913  )
914  );
915 
916  $KeyPurposeId = array('type' => ASN1::TYPE_OBJECT_IDENTIFIER);
917 
918  $this->ExtKeyUsageSyntax = array(
919  'type' => ASN1::TYPE_SEQUENCE,
920  'min' => 1,
921  'max' => -1,
922  'children' => $KeyPurposeId
923  );
924 
925  $AccessDescription = array(
926  'type' => ASN1::TYPE_SEQUENCE,
927  'children' => array(
928  'accessMethod' => array('type' => ASN1::TYPE_OBJECT_IDENTIFIER),
929  'accessLocation' => $GeneralName
930  )
931  );
932 
933  $this->AuthorityInfoAccessSyntax = array(
934  'type' => ASN1::TYPE_SEQUENCE,
935  'min' => 1,
936  'max' => -1,
937  'children' => $AccessDescription
938  );
939 
940  $this->SubjectAltName = $GeneralNames;
941 
942  $this->PrivateKeyUsagePeriod = array(
943  'type' => ASN1::TYPE_SEQUENCE,
944  'children' => array(
945  'notBefore' => array(
946  'constant' => 0,
947  'optional' => true,
948  'implicit' => true,
949  'type' => ASN1::TYPE_GENERALIZED_TIME),
950  'notAfter' => array(
951  'constant' => 1,
952  'optional' => true,
953  'implicit' => true,
954  'type' => ASN1::TYPE_GENERALIZED_TIME)
955  )
956  );
957 
958  $BaseDistance = array('type' => ASN1::TYPE_INTEGER);
959 
960  $GeneralSubtree = array(
961  'type' => ASN1::TYPE_SEQUENCE,
962  'children' => array(
963  'base' => $GeneralName,
964  'minimum' => array(
965  'constant' => 0,
966  'optional' => true,
967  'implicit' => true,
968  'default' => new BigInteger(0)
969  ) + $BaseDistance,
970  'maximum' => array(
971  'constant' => 1,
972  'optional' => true,
973  'implicit' => true,
974  ) + $BaseDistance
975  )
976  );
977 
978  $GeneralSubtrees = array(
979  'type' => ASN1::TYPE_SEQUENCE,
980  'min' => 1,
981  'max' => -1,
982  'children' => $GeneralSubtree
983  );
984 
985  $this->NameConstraints = array(
986  'type' => ASN1::TYPE_SEQUENCE,
987  'children' => array(
988  'permittedSubtrees' => array(
989  'constant' => 0,
990  'optional' => true,
991  'implicit' => true
992  ) + $GeneralSubtrees,
993  'excludedSubtrees' => array(
994  'constant' => 1,
995  'optional' => true,
996  'implicit' => true
997  ) + $GeneralSubtrees
998  )
999  );
1000 
1001  $this->CPSuri = array('type' => ASN1::TYPE_IA5_STRING);
1002 
1003  $DisplayText = array(
1004  'type' => ASN1::TYPE_CHOICE,
1005  'children' => array(
1006  'ia5String' => array('type' => ASN1::TYPE_IA5_STRING),
1007  'visibleString' => array('type' => ASN1::TYPE_VISIBLE_STRING),
1008  'bmpString' => array('type' => ASN1::TYPE_BMP_STRING),
1009  'utf8String' => array('type' => ASN1::TYPE_UTF8_STRING)
1010  )
1011  );
1012 
1013  $NoticeReference = array(
1014  'type' => ASN1::TYPE_SEQUENCE,
1015  'children' => array(
1016  'organization' => $DisplayText,
1017  'noticeNumbers' => array(
1018  'type' => ASN1::TYPE_SEQUENCE,
1019  'min' => 1,
1020  'max' => 200,
1021  'children' => array('type' => ASN1::TYPE_INTEGER)
1022  )
1023  )
1024  );
1025 
1026  $this->UserNotice = array(
1027  'type' => ASN1::TYPE_SEQUENCE,
1028  'children' => array(
1029  'noticeRef' => array(
1030  'optional' => true,
1031  'implicit' => true
1032  ) + $NoticeReference,
1033  'explicitText' => array(
1034  'optional' => true,
1035  'implicit' => true
1036  ) + $DisplayText
1037  )
1038  );
1039 
1040  // mapping is from <http://www.mozilla.org/projects/security/pki/nss/tech-notes/tn3.html>
1041  $this->netscape_cert_type = array(
1042  'type' => ASN1::TYPE_BIT_STRING,
1043  'mapping' => array(
1044  'SSLClient',
1045  'SSLServer',
1046  'Email',
1047  'ObjectSigning',
1048  'Reserved',
1049  'SSLCA',
1050  'EmailCA',
1051  'ObjectSigningCA'
1052  )
1053  );
1054 
1055  $this->netscape_comment = array('type' => ASN1::TYPE_IA5_STRING);
1056  $this->netscape_ca_policy_url = array('type' => ASN1::TYPE_IA5_STRING);
1057 
1058  // attribute is used in RFC2986 but we're using the RFC5280 definition
1059 
1060  $Attribute = array(
1061  'type' => ASN1::TYPE_SEQUENCE,
1062  'children' => array(
1063  'type' => $AttributeType,
1064  'value'=> array(
1065  'type' => ASN1::TYPE_SET,
1066  'min' => 1,
1067  'max' => -1,
1068  'children' => $this->AttributeValue
1069  )
1070  )
1071  );
1072 
1073  // adapted from <http://tools.ietf.org/html/rfc2986>
1074 
1075  $Attributes = array(
1076  'type' => ASN1::TYPE_SET,
1077  'min' => 1,
1078  'max' => -1,
1079  'children' => $Attribute
1080  );
1081 
1082  $CertificationRequestInfo = array(
1083  'type' => ASN1::TYPE_SEQUENCE,
1084  'children' => array(
1085  'version' => array(
1086  'type' => ASN1::TYPE_INTEGER,
1087  'mapping' => array('v1')
1088  ),
1089  'subject' => $this->Name,
1090  'subjectPKInfo' => $SubjectPublicKeyInfo,
1091  'attributes' => array(
1092  'constant' => 0,
1093  'optional' => true,
1094  'implicit' => true
1095  ) + $Attributes,
1096  )
1097  );
1098 
1099  $this->CertificationRequest = array(
1100  'type' => ASN1::TYPE_SEQUENCE,
1101  'children' => array(
1102  'certificationRequestInfo' => $CertificationRequestInfo,
1103  'signatureAlgorithm' => $AlgorithmIdentifier,
1104  'signature' => array('type' => ASN1::TYPE_BIT_STRING)
1105  )
1106  );
1107 
1108  $RevokedCertificate = array(
1109  'type' => ASN1::TYPE_SEQUENCE,
1110  'children' => array(
1111  'userCertificate' => $CertificateSerialNumber,
1112  'revocationDate' => $Time,
1113  'crlEntryExtensions' => array(
1114  'optional' => true
1115  ) + $this->Extensions
1116  )
1117  );
1118 
1119  $TBSCertList = array(
1120  'type' => ASN1::TYPE_SEQUENCE,
1121  'children' => array(
1122  'version' => array(
1123  'optional' => true,
1124  'default' => 'v1'
1125  ) + $Version,
1126  'signature' => $AlgorithmIdentifier,
1127  'issuer' => $this->Name,
1128  'thisUpdate' => $Time,
1129  'nextUpdate' => array(
1130  'optional' => true
1131  ) + $Time,
1132  'revokedCertificates' => array(
1133  'type' => ASN1::TYPE_SEQUENCE,
1134  'optional' => true,
1135  'min' => 0,
1136  'max' => -1,
1137  'children' => $RevokedCertificate
1138  ),
1139  'crlExtensions' => array(
1140  'constant' => 0,
1141  'optional' => true,
1142  'explicit' => true
1143  ) + $this->Extensions
1144  )
1145  );
1146 
1147  $this->CertificateList = array(
1148  'type' => ASN1::TYPE_SEQUENCE,
1149  'children' => array(
1150  'tbsCertList' => $TBSCertList,
1151  'signatureAlgorithm' => $AlgorithmIdentifier,
1152  'signature' => array('type' => ASN1::TYPE_BIT_STRING)
1153  )
1154  );
1155 
1156  $this->CRLNumber = array('type' => ASN1::TYPE_INTEGER);
1157 
1158  $this->CRLReason = array('type' => ASN1::TYPE_ENUMERATED,
1159  'mapping' => array(
1160  'unspecified',
1161  'keyCompromise',
1162  'cACompromise',
1163  'affiliationChanged',
1164  'superseded',
1165  'cessationOfOperation',
1166  'certificateHold',
1167  // Value 7 is not used.
1168  8 => 'removeFromCRL',
1169  'privilegeWithdrawn',
1170  'aACompromise'
1171  )
1172  );
1173 
1174  $this->IssuingDistributionPoint = array('type' => ASN1::TYPE_SEQUENCE,
1175  'children' => array(
1176  'distributionPoint' => array(
1177  'constant' => 0,
1178  'optional' => true,
1179  'explicit' => true
1180  ) + $DistributionPointName,
1181  'onlyContainsUserCerts' => array(
1182  'type' => ASN1::TYPE_BOOLEAN,
1183  'constant' => 1,
1184  'optional' => true,
1185  'default' => false,
1186  'implicit' => true
1187  ),
1188  'onlyContainsCACerts' => array(
1189  'type' => ASN1::TYPE_BOOLEAN,
1190  'constant' => 2,
1191  'optional' => true,
1192  'default' => false,
1193  'implicit' => true
1194  ),
1195  'onlySomeReasons' => array(
1196  'constant' => 3,
1197  'optional' => true,
1198  'implicit' => true
1199  ) + $ReasonFlags,
1200  'indirectCRL' => array(
1201  'type' => ASN1::TYPE_BOOLEAN,
1202  'constant' => 4,
1203  'optional' => true,
1204  'default' => false,
1205  'implicit' => true
1206  ),
1207  'onlyContainsAttributeCerts' => array(
1208  'type' => ASN1::TYPE_BOOLEAN,
1209  'constant' => 5,
1210  'optional' => true,
1211  'default' => false,
1212  'implicit' => true
1213  )
1214  )
1215  );
1216 
1217  $this->InvalidityDate = array('type' => ASN1::TYPE_GENERALIZED_TIME);
1218 
1219  $this->CertificateIssuer = $GeneralNames;
1220 
1221  $this->HoldInstructionCode = array('type' => ASN1::TYPE_OBJECT_IDENTIFIER);
1222 
1223  $PublicKeyAndChallenge = array(
1224  'type' => ASN1::TYPE_SEQUENCE,
1225  'children' => array(
1226  'spki' => $SubjectPublicKeyInfo,
1227  'challenge' => array('type' => ASN1::TYPE_IA5_STRING)
1228  )
1229  );
1230 
1231  $this->SignedPublicKeyAndChallenge = array(
1232  'type' => ASN1::TYPE_SEQUENCE,
1233  'children' => array(
1234  'publicKeyAndChallenge' => $PublicKeyAndChallenge,
1235  'signatureAlgorithm' => $AlgorithmIdentifier,
1236  'signature' => array('type' => ASN1::TYPE_BIT_STRING)
1237  )
1238  );
1239 
1240  // OIDs from RFC5280 and those RFCs mentioned in RFC5280#section-4.1.1.2
1241  $this->oids = array(
1242  '1.3.6.1.5.5.7' => 'id-pkix',
1243  '1.3.6.1.5.5.7.1' => 'id-pe',
1244  '1.3.6.1.5.5.7.2' => 'id-qt',
1245  '1.3.6.1.5.5.7.3' => 'id-kp',
1246  '1.3.6.1.5.5.7.48' => 'id-ad',
1247  '1.3.6.1.5.5.7.2.1' => 'id-qt-cps',
1248  '1.3.6.1.5.5.7.2.2' => 'id-qt-unotice',
1249  '1.3.6.1.5.5.7.48.1' =>'id-ad-ocsp',
1250  '1.3.6.1.5.5.7.48.2' => 'id-ad-caIssuers',
1251  '1.3.6.1.5.5.7.48.3' => 'id-ad-timeStamping',
1252  '1.3.6.1.5.5.7.48.5' => 'id-ad-caRepository',
1253  '2.5.4' => 'id-at',
1254  '2.5.4.41' => 'id-at-name',
1255  '2.5.4.4' => 'id-at-surname',
1256  '2.5.4.42' => 'id-at-givenName',
1257  '2.5.4.43' => 'id-at-initials',
1258  '2.5.4.44' => 'id-at-generationQualifier',
1259  '2.5.4.3' => 'id-at-commonName',
1260  '2.5.4.7' => 'id-at-localityName',
1261  '2.5.4.8' => 'id-at-stateOrProvinceName',
1262  '2.5.4.10' => 'id-at-organizationName',
1263  '2.5.4.11' => 'id-at-organizationalUnitName',
1264  '2.5.4.12' => 'id-at-title',
1265  '2.5.4.13' => 'id-at-description',
1266  '2.5.4.46' => 'id-at-dnQualifier',
1267  '2.5.4.6' => 'id-at-countryName',
1268  '2.5.4.5' => 'id-at-serialNumber',
1269  '2.5.4.65' => 'id-at-pseudonym',
1270  '2.5.4.17' => 'id-at-postalCode',
1271  '2.5.4.9' => 'id-at-streetAddress',
1272  '2.5.4.45' => 'id-at-uniqueIdentifier',
1273  '2.5.4.72' => 'id-at-role',
1274 
1275  '0.9.2342.19200300.100.1.25' => 'id-domainComponent',
1276  '1.2.840.113549.1.9' => 'pkcs-9',
1277  '1.2.840.113549.1.9.1' => 'pkcs-9-at-emailAddress',
1278  '2.5.29' => 'id-ce',
1279  '2.5.29.35' => 'id-ce-authorityKeyIdentifier',
1280  '2.5.29.14' => 'id-ce-subjectKeyIdentifier',
1281  '2.5.29.15' => 'id-ce-keyUsage',
1282  '2.5.29.16' => 'id-ce-privateKeyUsagePeriod',
1283  '2.5.29.32' => 'id-ce-certificatePolicies',
1284  '2.5.29.32.0' => 'anyPolicy',
1285 
1286  '2.5.29.33' => 'id-ce-policyMappings',
1287  '2.5.29.17' => 'id-ce-subjectAltName',
1288  '2.5.29.18' => 'id-ce-issuerAltName',
1289  '2.5.29.9' => 'id-ce-subjectDirectoryAttributes',
1290  '2.5.29.19' => 'id-ce-basicConstraints',
1291  '2.5.29.30' => 'id-ce-nameConstraints',
1292  '2.5.29.36' => 'id-ce-policyConstraints',
1293  '2.5.29.31' => 'id-ce-cRLDistributionPoints',
1294  '2.5.29.37' => 'id-ce-extKeyUsage',
1295  '2.5.29.37.0' => 'anyExtendedKeyUsage',
1296  '1.3.6.1.5.5.7.3.1' => 'id-kp-serverAuth',
1297  '1.3.6.1.5.5.7.3.2' => 'id-kp-clientAuth',
1298  '1.3.6.1.5.5.7.3.3' => 'id-kp-codeSigning',
1299  '1.3.6.1.5.5.7.3.4' => 'id-kp-emailProtection',
1300  '1.3.6.1.5.5.7.3.8' => 'id-kp-timeStamping',
1301  '1.3.6.1.5.5.7.3.9' => 'id-kp-OCSPSigning',
1302  '2.5.29.54' => 'id-ce-inhibitAnyPolicy',
1303  '2.5.29.46' => 'id-ce-freshestCRL',
1304  '1.3.6.1.5.5.7.1.1' => 'id-pe-authorityInfoAccess',
1305  '1.3.6.1.5.5.7.1.11' => 'id-pe-subjectInfoAccess',
1306  '2.5.29.20' => 'id-ce-cRLNumber',
1307  '2.5.29.28' => 'id-ce-issuingDistributionPoint',
1308  '2.5.29.27' => 'id-ce-deltaCRLIndicator',
1309  '2.5.29.21' => 'id-ce-cRLReasons',
1310  '2.5.29.29' => 'id-ce-certificateIssuer',
1311  '2.5.29.23' => 'id-ce-holdInstructionCode',
1312  '1.2.840.10040.2' => 'holdInstruction',
1313  '1.2.840.10040.2.1' => 'id-holdinstruction-none',
1314  '1.2.840.10040.2.2' => 'id-holdinstruction-callissuer',
1315  '1.2.840.10040.2.3' => 'id-holdinstruction-reject',
1316  '2.5.29.24' => 'id-ce-invalidityDate',
1317 
1318  '1.2.840.113549.2.2' => 'md2',
1319  '1.2.840.113549.2.5' => 'md5',
1320  '1.3.14.3.2.26' => 'id-sha1',
1321  '1.2.840.10040.4.1' => 'id-dsa',
1322  '1.2.840.10040.4.3' => 'id-dsa-with-sha1',
1323  '1.2.840.113549.1.1' => 'pkcs-1',
1324  '1.2.840.113549.1.1.1' => 'rsaEncryption',
1325  '1.2.840.113549.1.1.2' => 'md2WithRSAEncryption',
1326  '1.2.840.113549.1.1.4' => 'md5WithRSAEncryption',
1327  '1.2.840.113549.1.1.5' => 'sha1WithRSAEncryption',
1328  '1.2.840.10046.2.1' => 'dhpublicnumber',
1329  '2.16.840.1.101.2.1.1.22' => 'id-keyExchangeAlgorithm',
1330  '1.2.840.10045' => 'ansi-X9-62',
1331  '1.2.840.10045.4' => 'id-ecSigType',
1332  '1.2.840.10045.4.1' => 'ecdsa-with-SHA1',
1333  '1.2.840.10045.1' => 'id-fieldType',
1334  '1.2.840.10045.1.1' => 'prime-field',
1335  '1.2.840.10045.1.2' => 'characteristic-two-field',
1336  '1.2.840.10045.1.2.3' => 'id-characteristic-two-basis',
1337  '1.2.840.10045.1.2.3.1' => 'gnBasis',
1338  '1.2.840.10045.1.2.3.2' => 'tpBasis',
1339  '1.2.840.10045.1.2.3.3' => 'ppBasis',
1340  '1.2.840.10045.2' => 'id-publicKeyType',
1341  '1.2.840.10045.2.1' => 'id-ecPublicKey',
1342  '1.2.840.10045.3' => 'ellipticCurve',
1343  '1.2.840.10045.3.0' => 'c-TwoCurve',
1344  '1.2.840.10045.3.0.1' => 'c2pnb163v1',
1345  '1.2.840.10045.3.0.2' => 'c2pnb163v2',
1346  '1.2.840.10045.3.0.3' => 'c2pnb163v3',
1347  '1.2.840.10045.3.0.4' => 'c2pnb176w1',
1348  '1.2.840.10045.3.0.5' => 'c2pnb191v1',
1349  '1.2.840.10045.3.0.6' => 'c2pnb191v2',
1350  '1.2.840.10045.3.0.7' => 'c2pnb191v3',
1351  '1.2.840.10045.3.0.8' => 'c2pnb191v4',
1352  '1.2.840.10045.3.0.9' => 'c2pnb191v5',
1353  '1.2.840.10045.3.0.10' => 'c2pnb208w1',
1354  '1.2.840.10045.3.0.11' => 'c2pnb239v1',
1355  '1.2.840.10045.3.0.12' => 'c2pnb239v2',
1356  '1.2.840.10045.3.0.13' => 'c2pnb239v3',
1357  '1.2.840.10045.3.0.14' => 'c2pnb239v4',
1358  '1.2.840.10045.3.0.15' => 'c2pnb239v5',
1359  '1.2.840.10045.3.0.16' => 'c2pnb272w1',
1360  '1.2.840.10045.3.0.17' => 'c2pnb304w1',
1361  '1.2.840.10045.3.0.18' => 'c2pnb359v1',
1362  '1.2.840.10045.3.0.19' => 'c2pnb368w1',
1363  '1.2.840.10045.3.0.20' => 'c2pnb431r1',
1364  '1.2.840.10045.3.1' => 'primeCurve',
1365  '1.2.840.10045.3.1.1' => 'prime192v1',
1366  '1.2.840.10045.3.1.2' => 'prime192v2',
1367  '1.2.840.10045.3.1.3' => 'prime192v3',
1368  '1.2.840.10045.3.1.4' => 'prime239v1',
1369  '1.2.840.10045.3.1.5' => 'prime239v2',
1370  '1.2.840.10045.3.1.6' => 'prime239v3',
1371  '1.2.840.10045.3.1.7' => 'prime256v1',
1372  '1.2.840.113549.1.1.7' => 'id-RSAES-OAEP',
1373  '1.2.840.113549.1.1.9' => 'id-pSpecified',
1374  '1.2.840.113549.1.1.10' => 'id-RSASSA-PSS',
1375  '1.2.840.113549.1.1.8' => 'id-mgf1',
1376  '1.2.840.113549.1.1.14' => 'sha224WithRSAEncryption',
1377  '1.2.840.113549.1.1.11' => 'sha256WithRSAEncryption',
1378  '1.2.840.113549.1.1.12' => 'sha384WithRSAEncryption',
1379  '1.2.840.113549.1.1.13' => 'sha512WithRSAEncryption',
1380  '2.16.840.1.101.3.4.2.4' => 'id-sha224',
1381  '2.16.840.1.101.3.4.2.1' => 'id-sha256',
1382  '2.16.840.1.101.3.4.2.2' => 'id-sha384',
1383  '2.16.840.1.101.3.4.2.3' => 'id-sha512',
1384  '1.2.643.2.2.4' => 'id-GostR3411-94-with-GostR3410-94',
1385  '1.2.643.2.2.3' => 'id-GostR3411-94-with-GostR3410-2001',
1386  '1.2.643.2.2.20' => 'id-GostR3410-2001',
1387  '1.2.643.2.2.19' => 'id-GostR3410-94',
1388  // Netscape Object Identifiers from "Netscape Certificate Extensions"
1389  '2.16.840.1.113730' => 'netscape',
1390  '2.16.840.1.113730.1' => 'netscape-cert-extension',
1391  '2.16.840.1.113730.1.1' => 'netscape-cert-type',
1392  '2.16.840.1.113730.1.13' => 'netscape-comment',
1393  '2.16.840.1.113730.1.8' => 'netscape-ca-policy-url',
1394  // the following are X.509 extensions not supported by phpseclib
1395  '1.3.6.1.5.5.7.1.12' => 'id-pe-logotype',
1396  '1.2.840.113533.7.65.0' => 'entrustVersInfo',
1397  '2.16.840.1.113733.1.6.9' => 'verisignPrivate',
1398  // for Certificate Signing Requests
1399  // see http://tools.ietf.org/html/rfc2985
1400  '1.2.840.113549.1.9.2' => 'pkcs-9-at-unstructuredName', // PKCS #9 unstructured name
1401  '1.2.840.113549.1.9.7' => 'pkcs-9-at-challengePassword', // Challenge password for certificate revocations
1402  '1.2.840.113549.1.9.14' => 'pkcs-9-at-extensionRequest' // Certificate extension request
1403  );
1404  }
1405 
1416  function loadX509($cert, $mode = self::FORMAT_AUTO_DETECT)
1417  {
1418  if (is_array($cert) && isset($cert['tbsCertificate'])) {
1419  unset($this->currentCert);
1420  unset($this->currentKeyIdentifier);
1421  $this->dn = $cert['tbsCertificate']['subject'];
1422  if (!isset($this->dn)) {
1423  return false;
1424  }
1425  $this->currentCert = $cert;
1426 
1427  $currentKeyIdentifier = $this->getExtension('id-ce-subjectKeyIdentifier');
1428  $this->currentKeyIdentifier = is_string($currentKeyIdentifier) ? $currentKeyIdentifier : null;
1429 
1430  unset($this->signatureSubject);
1431 
1432  return $cert;
1433  }
1434 
1435  $asn1 = new ASN1();
1436 
1437  if ($mode != self::FORMAT_DER) {
1438  $newcert = $this->_extractBER($cert);
1439  if ($mode == self::FORMAT_PEM && $cert == $newcert) {
1440  return false;
1441  }
1442  $cert = $newcert;
1443  }
1444 
1445  if ($cert === false) {
1446  $this->currentCert = false;
1447  return false;
1448  }
1449 
1450  $asn1->loadOIDs($this->oids);
1451  $decoded = $asn1->decodeBER($cert);
1452 
1453  if (!empty($decoded)) {
1454  $x509 = $asn1->asn1map($decoded[0], $this->Certificate);
1455  }
1456  if (!isset($x509) || $x509 === false) {
1457  $this->currentCert = false;
1458  return false;
1459  }
1460 
1461  $this->signatureSubject = substr($cert, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);
1462 
1463  $this->_mapInExtensions($x509, 'tbsCertificate/extensions', $asn1);
1464 
1465  $key = &$x509['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'];
1466  $key = $this->_reformatKey($x509['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'], $key);
1467 
1468  $this->currentCert = $x509;
1469  $this->dn = $x509['tbsCertificate']['subject'];
1470 
1471  $currentKeyIdentifier = $this->getExtension('id-ce-subjectKeyIdentifier');
1472  $this->currentKeyIdentifier = is_string($currentKeyIdentifier) ? $currentKeyIdentifier : null;
1473 
1474  return $x509;
1475  }
1476 
1485  function saveX509($cert, $format = self::FORMAT_PEM)
1486  {
1487  if (!is_array($cert) || !isset($cert['tbsCertificate'])) {
1488  return false;
1489  }
1490 
1491  switch (true) {
1492  // "case !$a: case !$b: break; default: whatever();" is the same thing as "if ($a && $b) whatever()"
1493  case !($algorithm = $this->_subArray($cert, 'tbsCertificate/subjectPublicKeyInfo/algorithm/algorithm')):
1494  case is_object($cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']):
1495  break;
1496  default:
1497  switch ($algorithm) {
1498  case 'rsaEncryption':
1499  $cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']
1500  = base64_encode("\0" . base64_decode(preg_replace('#-.+-|[\r\n]#', '', $cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'])));
1501  /* "[For RSA keys] the parameters field MUST have ASN.1 type NULL for this algorithm identifier."
1502  -- https://tools.ietf.org/html/rfc3279#section-2.3.1
1503 
1504  given that and the fact that RSA keys appear ot be the only key type for which the parameters field can be blank,
1505  it seems like perhaps the ASN.1 description ought not say the parameters field is OPTIONAL, but whatever.
1506  */
1507  $cert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['parameters'] = null;
1508  // https://tools.ietf.org/html/rfc3279#section-2.2.1
1509  $cert['signatureAlgorithm']['parameters'] = null;
1510  $cert['tbsCertificate']['signature']['parameters'] = null;
1511  }
1512  }
1513 
1514  $asn1 = new ASN1();
1515  $asn1->loadOIDs($this->oids);
1516 
1517  $filters = array();
1518  $type_utf8_string = array('type' => ASN1::TYPE_UTF8_STRING);
1519  $filters['tbsCertificate']['signature']['parameters'] = $type_utf8_string;
1520  $filters['tbsCertificate']['signature']['issuer']['rdnSequence']['value'] = $type_utf8_string;
1521  $filters['tbsCertificate']['issuer']['rdnSequence']['value'] = $type_utf8_string;
1522  $filters['tbsCertificate']['subject']['rdnSequence']['value'] = $type_utf8_string;
1523  $filters['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['parameters'] = $type_utf8_string;
1524  $filters['signatureAlgorithm']['parameters'] = $type_utf8_string;
1525  $filters['authorityCertIssuer']['directoryName']['rdnSequence']['value'] = $type_utf8_string;
1526  //$filters['policyQualifiers']['qualifier'] = $type_utf8_string;
1527  $filters['distributionPoint']['fullName']['directoryName']['rdnSequence']['value'] = $type_utf8_string;
1528  $filters['directoryName']['rdnSequence']['value'] = $type_utf8_string;
1529 
1530  /* in the case of policyQualifiers/qualifier, the type has to be \phpseclib\File\ASN1::TYPE_IA5_STRING.
1531  \phpseclib\File\ASN1::TYPE_PRINTABLE_STRING will cause OpenSSL's X.509 parser to spit out random
1532  characters.
1533  */
1534  $filters['policyQualifiers']['qualifier']
1535  = array('type' => ASN1::TYPE_IA5_STRING);
1536 
1537  $asn1->loadFilters($filters);
1538 
1539  $this->_mapOutExtensions($cert, 'tbsCertificate/extensions', $asn1);
1540 
1541  $cert = $asn1->encodeDER($cert, $this->Certificate);
1542 
1543  switch ($format) {
1544  case self::FORMAT_DER:
1545  return $cert;
1546  // case self::FORMAT_PEM:
1547  default:
1548  return "-----BEGIN CERTIFICATE-----\r\n" . chunk_split(base64_encode($cert), 64) . '-----END CERTIFICATE-----';
1549  }
1550  }
1551 
1561  function _mapInExtensions(&$root, $path, $asn1)
1562  {
1563  $extensions = &$this->_subArray($root, $path);
1564 
1565  if (is_array($extensions)) {
1566  for ($i = 0; $i < count($extensions); $i++) {
1567  $id = $extensions[$i]['extnId'];
1568  $value = &$extensions[$i]['extnValue'];
1569  $value = base64_decode($value);
1570  $decoded = $asn1->decodeBER($value);
1571  /* [extnValue] contains the DER encoding of an ASN.1 value
1572  corresponding to the extension type identified by extnID */
1573  $map = $this->_getMapping($id);
1574  if (!is_bool($map)) {
1575  $mapped = $asn1->asn1map($decoded[0], $map, array('iPAddress' => array($this, '_decodeIP')));
1576  $value = $mapped === false ? $decoded[0] : $mapped;
1577 
1578  if ($id == 'id-ce-certificatePolicies') {
1579  for ($j = 0; $j < count($value); $j++) {
1580  if (!isset($value[$j]['policyQualifiers'])) {
1581  continue;
1582  }
1583  for ($k = 0; $k < count($value[$j]['policyQualifiers']); $k++) {
1584  $subid = $value[$j]['policyQualifiers'][$k]['policyQualifierId'];
1585  $map = $this->_getMapping($subid);
1586  $subvalue = &$value[$j]['policyQualifiers'][$k]['qualifier'];
1587  if ($map !== false) {
1588  $decoded = $asn1->decodeBER($subvalue);
1589  $mapped = $asn1->asn1map($decoded[0], $map);
1590  $subvalue = $mapped === false ? $decoded[0] : $mapped;
1591  }
1592  }
1593  }
1594  }
1595  } else {
1596  $value = base64_encode($value);
1597  }
1598  }
1599  }
1600  }
1601 
1611  function _mapOutExtensions(&$root, $path, $asn1)
1612  {
1613  $extensions = &$this->_subArray($root, $path);
1614 
1615  if (is_array($extensions)) {
1616  $size = count($extensions);
1617  for ($i = 0; $i < $size; $i++) {
1618  if ($extensions[$i] instanceof Element) {
1619  continue;
1620  }
1621 
1622  $id = $extensions[$i]['extnId'];
1623  $value = &$extensions[$i]['extnValue'];
1624 
1625  switch ($id) {
1626  case 'id-ce-certificatePolicies':
1627  for ($j = 0; $j < count($value); $j++) {
1628  if (!isset($value[$j]['policyQualifiers'])) {
1629  continue;
1630  }
1631  for ($k = 0; $k < count($value[$j]['policyQualifiers']); $k++) {
1632  $subid = $value[$j]['policyQualifiers'][$k]['policyQualifierId'];
1633  $map = $this->_getMapping($subid);
1634  $subvalue = &$value[$j]['policyQualifiers'][$k]['qualifier'];
1635  if ($map !== false) {
1636  // by default \phpseclib\File\ASN1 will try to render qualifier as a \phpseclib\File\ASN1::TYPE_IA5_STRING since it's
1637  // actual type is \phpseclib\File\ASN1::TYPE_ANY
1638  $subvalue = new Element($asn1->encodeDER($subvalue, $map));
1639  }
1640  }
1641  }
1642  break;
1643  case 'id-ce-authorityKeyIdentifier': // use 00 as the serial number instead of an empty string
1644  if (isset($value['authorityCertSerialNumber'])) {
1645  if ($value['authorityCertSerialNumber']->toBytes() == '') {
1646  $temp = chr((ASN1::CLASS_CONTEXT_SPECIFIC << 6) | 2) . "\1\0";
1647  $value['authorityCertSerialNumber'] = new Element($temp);
1648  }
1649  }
1650  }
1651 
1652  /* [extnValue] contains the DER encoding of an ASN.1 value
1653  corresponding to the extension type identified by extnID */
1654  $map = $this->_getMapping($id);
1655  if (is_bool($map)) {
1656  if (!$map) {
1657  user_error($id . ' is not a currently supported extension');
1658  unset($extensions[$i]);
1659  }
1660  } else {
1661  $temp = $asn1->encodeDER($value, $map, array('iPAddress' => array($this, '_encodeIP')));
1662  $value = base64_encode($temp);
1663  }
1664  }
1665  }
1666  }
1667 
1677  function _mapInAttributes(&$root, $path, $asn1)
1678  {
1679  $attributes = &$this->_subArray($root, $path);
1680 
1681  if (is_array($attributes)) {
1682  for ($i = 0; $i < count($attributes); $i++) {
1683  $id = $attributes[$i]['type'];
1684  /* $value contains the DER encoding of an ASN.1 value
1685  corresponding to the attribute type identified by type */
1686  $map = $this->_getMapping($id);
1687  if (is_array($attributes[$i]['value'])) {
1688  $values = &$attributes[$i]['value'];
1689  for ($j = 0; $j < count($values); $j++) {
1690  $value = $asn1->encodeDER($values[$j], $this->AttributeValue);
1691  $decoded = $asn1->decodeBER($value);
1692  if (!is_bool($map)) {
1693  $mapped = $asn1->asn1map($decoded[0], $map);
1694  if ($mapped !== false) {
1695  $values[$j] = $mapped;
1696  }
1697  if ($id == 'pkcs-9-at-extensionRequest') {
1698  $this->_mapInExtensions($values, $j, $asn1);
1699  }
1700  } elseif ($map) {
1701  $values[$j] = base64_encode($value);
1702  }
1703  }
1704  }
1705  }
1706  }
1707  }
1708 
1718  function _mapOutAttributes(&$root, $path, $asn1)
1719  {
1720  $attributes = &$this->_subArray($root, $path);
1721 
1722  if (is_array($attributes)) {
1723  $size = count($attributes);
1724  for ($i = 0; $i < $size; $i++) {
1725  /* [value] contains the DER encoding of an ASN.1 value
1726  corresponding to the attribute type identified by type */
1727  $id = $attributes[$i]['type'];
1728  $map = $this->_getMapping($id);
1729  if ($map === false) {
1730  user_error($id . ' is not a currently supported attribute', E_USER_NOTICE);
1731  unset($attributes[$i]);
1732  } elseif (is_array($attributes[$i]['value'])) {
1733  $values = &$attributes[$i]['value'];
1734  for ($j = 0; $j < count($values); $j++) {
1735  switch ($id) {
1736  case 'pkcs-9-at-extensionRequest':
1737  $this->_mapOutExtensions($values, $j, $asn1);
1738  break;
1739  }
1740 
1741  if (!is_bool($map)) {
1742  $temp = $asn1->encodeDER($values[$j], $map);
1743  $decoded = $asn1->decodeBER($temp);
1744  $values[$j] = $asn1->asn1map($decoded[0], $this->AttributeValue);
1745  }
1746  }
1747  }
1748  }
1749  }
1750  }
1751 
1759  function _getMapping($extnId)
1760  {
1761  if (!is_string($extnId)) { // eg. if it's a \phpseclib\File\ASN1\Element object
1762  return true;
1763  }
1764 
1765  switch ($extnId) {
1766  case 'id-ce-keyUsage':
1767  return $this->KeyUsage;
1768  case 'id-ce-basicConstraints':
1769  return $this->BasicConstraints;
1770  case 'id-ce-subjectKeyIdentifier':
1771  return $this->KeyIdentifier;
1772  case 'id-ce-cRLDistributionPoints':
1774  case 'id-ce-authorityKeyIdentifier':
1776  case 'id-ce-certificatePolicies':
1778  case 'id-ce-extKeyUsage':
1779  return $this->ExtKeyUsageSyntax;
1780  case 'id-pe-authorityInfoAccess':
1782  case 'id-ce-subjectAltName':
1783  return $this->SubjectAltName;
1784  case 'id-ce-privateKeyUsagePeriod':
1786  case 'id-ce-issuerAltName':
1787  return $this->IssuerAltName;
1788  case 'id-ce-policyMappings':
1789  return $this->PolicyMappings;
1790  case 'id-ce-nameConstraints':
1791  return $this->NameConstraints;
1792 
1793  case 'netscape-cert-type':
1795  case 'netscape-comment':
1796  return $this->netscape_comment;
1797  case 'netscape-ca-policy-url':
1799 
1800  // since id-qt-cps isn't a constructed type it will have already been decoded as a string by the time it gets
1801  // back around to asn1map() and we don't want it decoded again.
1802  //case 'id-qt-cps':
1803  // return $this->CPSuri;
1804  case 'id-qt-unotice':
1805  return $this->UserNotice;
1806 
1807  // the following OIDs are unsupported but we don't want them to give notices when calling saveX509().
1808  case 'id-pe-logotype': // http://www.ietf.org/rfc/rfc3709.txt
1809  case 'entrustVersInfo':
1810  // http://support.microsoft.com/kb/287547
1811  case '1.3.6.1.4.1.311.20.2': // szOID_ENROLL_CERTTYPE_EXTENSION
1812  case '1.3.6.1.4.1.311.21.1': // szOID_CERTSRV_CA_VERSION
1813  // "SET Secure Electronic Transaction Specification"
1814  // http://www.maithean.com/docs/set_bk3.pdf
1815  case '2.23.42.7.0': // id-set-hashedRootKey
1816  return true;
1817 
1818  // CSR attributes
1819  case 'pkcs-9-at-unstructuredName':
1820  return $this->PKCS9String;
1821  case 'pkcs-9-at-challengePassword':
1822  return $this->DirectoryString;
1823  case 'pkcs-9-at-extensionRequest':
1824  return $this->Extensions;
1825 
1826  // CRL extensions.
1827  case 'id-ce-cRLNumber':
1828  return $this->CRLNumber;
1829  case 'id-ce-deltaCRLIndicator':
1830  return $this->CRLNumber;
1831  case 'id-ce-issuingDistributionPoint':
1833  case 'id-ce-freshestCRL':
1835  case 'id-ce-cRLReasons':
1836  return $this->CRLReason;
1837  case 'id-ce-invalidityDate':
1838  return $this->InvalidityDate;
1839  case 'id-ce-certificateIssuer':
1840  return $this->CertificateIssuer;
1841  case 'id-ce-holdInstructionCode':
1843  }
1844 
1845  return false;
1846  }
1847 
1855  function loadCA($cert)
1856  {
1857  $olddn = $this->dn;
1858  $oldcert = $this->currentCert;
1859  $oldsigsubj = $this->signatureSubject;
1860  $oldkeyid = $this->currentKeyIdentifier;
1861 
1862  $cert = $this->loadX509($cert);
1863  if (!$cert) {
1864  $this->dn = $olddn;
1865  $this->currentCert = $oldcert;
1866  $this->signatureSubject = $oldsigsubj;
1867  $this->currentKeyIdentifier = $oldkeyid;
1868 
1869  return false;
1870  }
1871 
1872  /* From RFC5280 "PKIX Certificate and CRL Profile":
1873 
1874  If the keyUsage extension is present, then the subject public key
1875  MUST NOT be used to verify signatures on certificates or CRLs unless
1876  the corresponding keyCertSign or cRLSign bit is set. */
1877  //$keyUsage = $this->getExtension('id-ce-keyUsage');
1878  //if ($keyUsage && !in_array('keyCertSign', $keyUsage)) {
1879  // return false;
1880  //}
1881 
1882  /* From RFC5280 "PKIX Certificate and CRL Profile":
1883 
1884  The cA boolean indicates whether the certified public key may be used
1885  to verify certificate signatures. If the cA boolean is not asserted,
1886  then the keyCertSign bit in the key usage extension MUST NOT be
1887  asserted. If the basic constraints extension is not present in a
1888  version 3 certificate, or the extension is present but the cA boolean
1889  is not asserted, then the certified public key MUST NOT be used to
1890  verify certificate signatures. */
1891  //$basicConstraints = $this->getExtension('id-ce-basicConstraints');
1892  //if (!$basicConstraints || !$basicConstraints['cA']) {
1893  // return false;
1894  //}
1895 
1896  $this->CAs[] = $cert;
1897 
1898  $this->dn = $olddn;
1899  $this->currentCert = $oldcert;
1900  $this->signatureSubject = $oldsigsubj;
1901 
1902  return true;
1903  }
1904 
1922  function validateURL($url)
1923  {
1924  if (!is_array($this->currentCert) || !isset($this->currentCert['tbsCertificate'])) {
1925  return false;
1926  }
1927 
1928  $components = parse_url($url);
1929  if (!isset($components['host'])) {
1930  return false;
1931  }
1932 
1933  if ($names = $this->getExtension('id-ce-subjectAltName')) {
1934  foreach ($names as $key => $value) {
1935  $value = str_replace(array('.', '*'), array('\.', '[^.]*'), $value);
1936  switch ($key) {
1937  case 'dNSName':
1938  /* From RFC2818 "HTTP over TLS":
1939 
1940  If a subjectAltName extension of type dNSName is present, that MUST
1941  be used as the identity. Otherwise, the (most specific) Common Name
1942  field in the Subject field of the certificate MUST be used. Although
1943  the use of the Common Name is existing practice, it is deprecated and
1944  Certification Authorities are encouraged to use the dNSName instead. */
1945  if (preg_match('#^' . $value . '$#', $components['host'])) {
1946  return true;
1947  }
1948  break;
1949  case 'iPAddress':
1950  /* From RFC2818 "HTTP over TLS":
1951 
1952  In some cases, the URI is specified as an IP address rather than a
1953  hostname. In this case, the iPAddress subjectAltName must be present
1954  in the certificate and must exactly match the IP in the URI. */
1955  if (preg_match('#(?:\d{1-3}\.){4}#', $components['host'] . '.') && preg_match('#^' . $value . '$#', $components['host'])) {
1956  return true;
1957  }
1958  }
1959  }
1960  return false;
1961  }
1962 
1963  if ($value = $this->getDNProp('id-at-commonName')) {
1964  $value = str_replace(array('.', '*'), array('\.', '[^.]*'), $value[0]);
1965  return preg_match('#^' . $value . '$#', $components['host']);
1966  }
1967 
1968  return false;
1969  }
1970 
1979  function validateDate($date = null)
1980  {
1981  if (!is_array($this->currentCert) || !isset($this->currentCert['tbsCertificate'])) {
1982  return false;
1983  }
1984 
1985  if (!isset($date)) {
1986  $date = time();
1987  }
1988 
1989  $notBefore = $this->currentCert['tbsCertificate']['validity']['notBefore'];
1990  $notBefore = isset($notBefore['generalTime']) ? $notBefore['generalTime'] : $notBefore['utcTime'];
1991 
1992  $notAfter = $this->currentCert['tbsCertificate']['validity']['notAfter'];
1993  $notAfter = isset($notAfter['generalTime']) ? $notAfter['generalTime'] : $notAfter['utcTime'];
1994 
1995  switch (true) {
1996  case $date < @strtotime($notBefore):
1997  case $date > @strtotime($notAfter):
1998  return false;
1999  }
2000 
2001  return true;
2002  }
2003 
2019  function validateSignature($caonly = true)
2020  {
2021  if (!is_array($this->currentCert) || !isset($this->signatureSubject)) {
2022  return null;
2023  }
2024 
2025  /* TODO:
2026  "emailAddress attribute values are not case-sensitive (e.g., "subscriber@example.com" is the same as "SUBSCRIBER@EXAMPLE.COM")."
2027  -- http://tools.ietf.org/html/rfc5280#section-4.1.2.6
2028 
2029  implement pathLenConstraint in the id-ce-basicConstraints extension */
2030 
2031  switch (true) {
2032  case isset($this->currentCert['tbsCertificate']):
2033  // self-signed cert
2034  if ($this->currentCert['tbsCertificate']['issuer'] === $this->currentCert['tbsCertificate']['subject']) {
2035  $authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier');
2036  $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier');
2037  switch (true) {
2038  case !is_array($authorityKey):
2039  case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
2040  $signingCert = $this->currentCert; // working cert
2041  }
2042  }
2043 
2044  if (!empty($this->CAs)) {
2045  for ($i = 0; $i < count($this->CAs); $i++) {
2046  // even if the cert is a self-signed one we still want to see if it's a CA;
2047  // if not, we'll conditionally return an error
2048  $ca = $this->CAs[$i];
2049  if ($this->currentCert['tbsCertificate']['issuer'] === $ca['tbsCertificate']['subject']) {
2050  $authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier');
2051  $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca);
2052  switch (true) {
2053  case !is_array($authorityKey):
2054  case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
2055  $signingCert = $ca; // working cert
2056  break 2;
2057  }
2058  }
2059  }
2060  if (count($this->CAs) == $i && $caonly) {
2061  return false;
2062  }
2063  } elseif (!isset($signingCert) || $caonly) {
2064  return false;
2065  }
2066  return $this->_validateSignature(
2067  $signingCert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'],
2068  $signingCert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'],
2069  $this->currentCert['signatureAlgorithm']['algorithm'],
2070  substr(base64_decode($this->currentCert['signature']), 1),
2071  $this->signatureSubject
2072  );
2073  case isset($this->currentCert['certificationRequestInfo']):
2074  return $this->_validateSignature(
2075  $this->currentCert['certificationRequestInfo']['subjectPKInfo']['algorithm']['algorithm'],
2076  $this->currentCert['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'],
2077  $this->currentCert['signatureAlgorithm']['algorithm'],
2078  substr(base64_decode($this->currentCert['signature']), 1),
2079  $this->signatureSubject
2080  );
2081  case isset($this->currentCert['publicKeyAndChallenge']):
2082  return $this->_validateSignature(
2083  $this->currentCert['publicKeyAndChallenge']['spki']['algorithm']['algorithm'],
2084  $this->currentCert['publicKeyAndChallenge']['spki']['subjectPublicKey'],
2085  $this->currentCert['signatureAlgorithm']['algorithm'],
2086  substr(base64_decode($this->currentCert['signature']), 1),
2087  $this->signatureSubject
2088  );
2089  case isset($this->currentCert['tbsCertList']):
2090  if (!empty($this->CAs)) {
2091  for ($i = 0; $i < count($this->CAs); $i++) {
2092  $ca = $this->CAs[$i];
2093  if ($this->currentCert['tbsCertList']['issuer'] === $ca['tbsCertificate']['subject']) {
2094  $authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier');
2095  $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca);
2096  switch (true) {
2097  case !is_array($authorityKey):
2098  case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
2099  $signingCert = $ca; // working cert
2100  break 2;
2101  }
2102  }
2103  }
2104  }
2105  if (!isset($signingCert)) {
2106  return false;
2107  }
2108  return $this->_validateSignature(
2109  $signingCert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'],
2110  $signingCert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'],
2111  $this->currentCert['signatureAlgorithm']['algorithm'],
2112  substr(base64_decode($this->currentCert['signature']), 1),
2113  $this->signatureSubject
2114  );
2115  default:
2116  return false;
2117  }
2118  }
2119 
2133  function _validateSignature($publicKeyAlgorithm, $publicKey, $signatureAlgorithm, $signature, $signatureSubject)
2134  {
2135  switch ($publicKeyAlgorithm) {
2136  case 'rsaEncryption':
2137  $rsa = new RSA();
2138  $rsa->loadKey($publicKey);
2139 
2140  switch ($signatureAlgorithm) {
2141  case 'md2WithRSAEncryption':
2142  case 'md5WithRSAEncryption':
2143  case 'sha1WithRSAEncryption':
2144  case 'sha224WithRSAEncryption':
2145  case 'sha256WithRSAEncryption':
2146  case 'sha384WithRSAEncryption':
2147  case 'sha512WithRSAEncryption':
2148  $rsa->setHash(preg_replace('#WithRSAEncryption$#', '', $signatureAlgorithm));
2149  $rsa->setSignatureMode(RSA::SIGNATURE_PKCS1);
2150  if (!@$rsa->verify($signatureSubject, $signature)) {
2151  return false;
2152  }
2153  break;
2154  default:
2155  return null;
2156  }
2157  break;
2158  default:
2159  return null;
2160  }
2161 
2162  return true;
2163  }
2164 
2175  function _reformatKey($algorithm, $key)
2176  {
2177  switch ($algorithm) {
2178  case 'rsaEncryption':
2179  return
2180  "-----BEGIN RSA PUBLIC KEY-----\r\n" .
2181  // subjectPublicKey is stored as a bit string in X.509 certs. the first byte of a bit string represents how many bits
2182  // in the last byte should be ignored. the following only supports non-zero stuff but as none of the X.509 certs Firefox
2183  // uses as a cert authority actually use a non-zero bit I think it's safe to assume that none do.
2184  chunk_split(base64_encode(substr(base64_decode($key), 1)), 64) .
2185  '-----END RSA PUBLIC KEY-----';
2186  default:
2187  return $key;
2188  }
2189  }
2190 
2200  function _decodeIP($ip)
2201  {
2202  $ip = base64_decode($ip);
2203  list(, $ip) = unpack('N', $ip);
2204  return long2ip($ip);
2205  }
2206 
2216  function _encodeIP($ip)
2217  {
2218  return base64_encode(pack('N', ip2long($ip)));
2219  }
2220 
2228  function _translateDNProp($propName)
2229  {
2230  switch (strtolower($propName)) {
2231  case 'id-at-countryname':
2232  case 'countryname':
2233  case 'c':
2234  return 'id-at-countryName';
2235  case 'id-at-organizationname':
2236  case 'organizationname':
2237  case 'o':
2238  return 'id-at-organizationName';
2239  case 'id-at-dnqualifier':
2240  case 'dnqualifier':
2241  return 'id-at-dnQualifier';
2242  case 'id-at-commonname':
2243  case 'commonname':
2244  case 'cn':
2245  return 'id-at-commonName';
2246  case 'id-at-stateorprovincename':
2247  case 'stateorprovincename':
2248  case 'state':
2249  case 'province':
2250  case 'provincename':
2251  case 'st':
2252  return 'id-at-stateOrProvinceName';
2253  case 'id-at-localityname':
2254  case 'localityname':
2255  case 'l':
2256  return 'id-at-localityName';
2257  case 'id-emailaddress':
2258  case 'emailaddress':
2259  return 'pkcs-9-at-emailAddress';
2260  case 'id-at-serialnumber':
2261  case 'serialnumber':
2262  return 'id-at-serialNumber';
2263  case 'id-at-postalcode':
2264  case 'postalcode':
2265  return 'id-at-postalCode';
2266  case 'id-at-streetaddress':
2267  case 'streetaddress':
2268  return 'id-at-streetAddress';
2269  case 'id-at-name':
2270  case 'name':
2271  return 'id-at-name';
2272  case 'id-at-givenname':
2273  case 'givenname':
2274  return 'id-at-givenName';
2275  case 'id-at-surname':
2276  case 'surname':
2277  case 'sn':
2278  return 'id-at-surname';
2279  case 'id-at-initials':
2280  case 'initials':
2281  return 'id-at-initials';
2282  case 'id-at-generationqualifier':
2283  case 'generationqualifier':
2284  return 'id-at-generationQualifier';
2285  case 'id-at-organizationalunitname':
2286  case 'organizationalunitname':
2287  case 'ou':
2288  return 'id-at-organizationalUnitName';
2289  case 'id-at-pseudonym':
2290  case 'pseudonym':
2291  return 'id-at-pseudonym';
2292  case 'id-at-title':
2293  case 'title':
2294  return 'id-at-title';
2295  case 'id-at-description':
2296  case 'description':
2297  return 'id-at-description';
2298  case 'id-at-role':
2299  case 'role':
2300  return 'id-at-role';
2301  case 'id-at-uniqueidentifier':
2302  case 'uniqueidentifier':
2303  case 'x500uniqueidentifier':
2304  return 'id-at-uniqueIdentifier';
2305  default:
2306  return false;
2307  }
2308  }
2309 
2319  function setDNProp($propName, $propValue, $type = 'utf8String')
2320  {
2321  if (empty($this->dn)) {
2322  $this->dn = array('rdnSequence' => array());
2323  }
2324 
2325  if (($propName = $this->_translateDNProp($propName)) === false) {
2326  return false;
2327  }
2328 
2329  foreach ((array) $propValue as $v) {
2330  if (!is_array($v) && isset($type)) {
2331  $v = array($type => $v);
2332  }
2333  $this->dn['rdnSequence'][] = array(
2334  array(
2335  'type' => $propName,
2336  'value'=> $v
2337  )
2338  );
2339  }
2340 
2341  return true;
2342  }
2343 
2350  function removeDNProp($propName)
2351  {
2352  if (empty($this->dn)) {
2353  return;
2354  }
2355 
2356  if (($propName = $this->_translateDNProp($propName)) === false) {
2357  return;
2358  }
2359 
2360  $dn = &$this->dn['rdnSequence'];
2361  $size = count($dn);
2362  for ($i = 0; $i < $size; $i++) {
2363  if ($dn[$i][0]['type'] == $propName) {
2364  unset($dn[$i]);
2365  }
2366  }
2367 
2368  $dn = array_values($dn);
2369  }
2370 
2380  function getDNProp($propName, $dn = null, $withType = false)
2381  {
2382  if (!isset($dn)) {
2383  $dn = $this->dn;
2384  }
2385 
2386  if (empty($dn)) {
2387  return false;
2388  }
2389 
2390  if (($propName = $this->_translateDNProp($propName)) === false) {
2391  return false;
2392  }
2393 
2394  $dn = $dn['rdnSequence'];
2395  $result = array();
2396  $asn1 = new ASN1();
2397  for ($i = 0; $i < count($dn); $i++) {
2398  if ($dn[$i][0]['type'] == $propName) {
2399  $v = $dn[$i][0]['value'];
2400  if (!$withType && is_array($v)) {
2401  foreach ($v as $type => $s) {
2402  $type = array_search($type, $asn1->ANYmap, true);
2403  if ($type !== false && isset($asn1->stringTypeSize[$type])) {
2404  $s = $asn1->convert($s, $type);
2405  if ($s !== false) {
2406  $v = $s;
2407  break;
2408  }
2409  }
2410  }
2411  if (is_array($v)) {
2412  $v = array_pop($v); // Always strip data type.
2413  }
2414  }
2415  $result[] = $v;
2416  }
2417  }
2418 
2419  return $result;
2420  }
2421 
2431  function setDN($dn, $merge = false, $type = 'utf8String')
2432  {
2433  if (!$merge) {
2434  $this->dn = null;
2435  }
2436 
2437  if (is_array($dn)) {
2438  if (isset($dn['rdnSequence'])) {
2439  $this->dn = $dn; // No merge here.
2440  return true;
2441  }
2442 
2443  // handles stuff generated by openssl_x509_parse()
2444  foreach ($dn as $prop => $value) {
2445  if (!$this->setDNProp($prop, $value, $type)) {
2446  return false;
2447  }
2448  }
2449  return true;
2450  }
2451 
2452  // handles everything else
2453  $results = preg_split('#((?:^|, *|/)(?:C=|O=|OU=|CN=|L=|ST=|SN=|postalCode=|streetAddress=|emailAddress=|serialNumber=|organizationalUnitName=|title=|description=|role=|x500UniqueIdentifier=))#', $dn, -1, PREG_SPLIT_DELIM_CAPTURE);
2454  for ($i = 1; $i < count($results); $i+=2) {
2455  $prop = trim($results[$i], ', =/');
2456  $value = $results[$i + 1];
2457  if (!$this->setDNProp($prop, $value, $type)) {
2458  return false;
2459  }
2460  }
2461 
2462  return true;
2463  }
2464 
2473  function getDN($format = self::DN_ARRAY, $dn = null)
2474  {
2475  if (!isset($dn)) {
2476  $dn = isset($this->currentCert['tbsCertList']) ? $this->currentCert['tbsCertList']['issuer'] : $this->dn;
2477  }
2478 
2479  switch ((int) $format) {
2480  case self::DN_ARRAY:
2481  return $dn;
2482  case self::DN_ASN1:
2483  $asn1 = new ASN1();
2484  $asn1->loadOIDs($this->oids);
2485  $filters = array();
2486  $filters['rdnSequence']['value'] = array('type' => ASN1::TYPE_UTF8_STRING);
2487  $asn1->loadFilters($filters);
2488  return $asn1->encodeDER($dn, $this->Name);
2489  case self::DN_OPENSSL:
2490  $dn = $this->getDN(self::DN_STRING, $dn);
2491  if ($dn === false) {
2492  return false;
2493  }
2494  $attrs = preg_split('#((?:^|, *|/)[a-z][a-z0-9]*=)#i', $dn, -1, PREG_SPLIT_DELIM_CAPTURE);
2495  $dn = array();
2496  for ($i = 1; $i < count($attrs); $i += 2) {
2497  $prop = trim($attrs[$i], ', =/');
2498  $value = $attrs[$i + 1];
2499  if (!isset($dn[$prop])) {
2500  $dn[$prop] = $value;
2501  } else {
2502  $dn[$prop] = array_merge((array) $dn[$prop], array($value));
2503  }
2504  }
2505  return $dn;
2506  case self::DN_CANON:
2507  // No SEQUENCE around RDNs and all string values normalized as
2508  // trimmed lowercase UTF-8 with all spacing as one blank.
2509  $asn1 = new ASN1();
2510  $asn1->loadOIDs($this->oids);
2511  $filters = array();
2512  $filters['value'] = array('type' => ASN1::TYPE_UTF8_STRING);
2513  $asn1->loadFilters($filters);
2514  $result = '';
2515  foreach ($dn['rdnSequence'] as $rdn) {
2516  foreach ($rdn as $i => $attr) {
2517  $attr = &$rdn[$i];
2518  if (is_array($attr['value'])) {
2519  foreach ($attr['value'] as $type => $v) {
2520  $type = array_search($type, $asn1->ANYmap, true);
2521  if ($type !== false && isset($asn1->stringTypeSize[$type])) {
2522  $v = $asn1->convert($v, $type);
2523  if ($v !== false) {
2524  $v = preg_replace('/\s+/', ' ', $v);
2525  $attr['value'] = strtolower(trim($v));
2526  break;
2527  }
2528  }
2529  }
2530  }
2531  }
2532  $result .= $asn1->encodeDER($rdn, $this->RelativeDistinguishedName);
2533  }
2534  return $result;
2535  case self::DN_HASH:
2536  $dn = $this->getDN(self::DN_CANON, $dn);
2537  $hash = new Hash('sha1');
2538  $hash = $hash->hash($dn);
2539  extract(unpack('Vhash', $hash));
2540  return strtolower(bin2hex(pack('N', $hash)));
2541  }
2542 
2543  // Default is to return a string.
2544  $start = true;
2545  $output = '';
2546  $asn1 = new ASN1();
2547  foreach ($dn['rdnSequence'] as $field) {
2548  $prop = $field[0]['type'];
2549  $value = $field[0]['value'];
2550 
2551  $delim = ', ';
2552  switch ($prop) {
2553  case 'id-at-countryName':
2554  $desc = 'C=';
2555  break;
2556  case 'id-at-stateOrProvinceName':
2557  $desc = 'ST=';
2558  break;
2559  case 'id-at-organizationName':
2560  $desc = 'O=';
2561  break;
2562  case 'id-at-organizationalUnitName':
2563  $desc = 'OU=';
2564  break;
2565  case 'id-at-commonName':
2566  $desc = 'CN=';
2567  break;
2568  case 'id-at-localityName':
2569  $desc = 'L=';
2570  break;
2571  case 'id-at-surname':
2572  $desc = 'SN=';
2573  break;
2574  case 'id-at-uniqueIdentifier':
2575  $delim = '/';
2576  $desc = 'x500UniqueIdentifier=';
2577  break;
2578  default:
2579  $delim = '/';
2580  $desc = preg_replace('#.+-([^-]+)$#', '$1', $prop) . '=';
2581  }
2582 
2583  if (!$start) {
2584  $output.= $delim;
2585  }
2586  if (is_array($value)) {
2587  foreach ($value as $type => $v) {
2588  $type = array_search($type, $asn1->ANYmap, true);
2589  if ($type !== false && isset($asn1->stringTypeSize[$type])) {
2590  $v = $asn1->convert($v, $type);
2591  if ($v !== false) {
2592  $value = $v;
2593  break;
2594  }
2595  }
2596  }
2597  if (is_array($value)) {
2598  $value = array_pop($value); // Always strip data type.
2599  }
2600  }
2601  $output.= $desc . $value;
2602  $start = false;
2603  }
2604 
2605  return $output;
2606  }
2607 
2615  function getIssuerDN($format = self::DN_ARRAY)
2616  {
2617  switch (true) {
2618  case !isset($this->currentCert) || !is_array($this->currentCert):
2619  break;
2620  case isset($this->currentCert['tbsCertificate']):
2621  return $this->getDN($format, $this->currentCert['tbsCertificate']['issuer']);
2622  case isset($this->currentCert['tbsCertList']):
2623  return $this->getDN($format, $this->currentCert['tbsCertList']['issuer']);
2624  }
2625 
2626  return false;
2627  }
2628 
2637  function getSubjectDN($format = self::DN_ARRAY)
2638  {
2639  switch (true) {
2640  case !empty($this->dn):
2641  return $this->getDN($format);
2642  case !isset($this->currentCert) || !is_array($this->currentCert):
2643  break;
2644  case isset($this->currentCert['tbsCertificate']):
2645  return $this->getDN($format, $this->currentCert['tbsCertificate']['subject']);
2646  case isset($this->currentCert['certificationRequestInfo']):
2647  return $this->getDN($format, $this->currentCert['certificationRequestInfo']['subject']);
2648  }
2649 
2650  return false;
2651  }
2652 
2661  function getIssuerDNProp($propName, $withType = false)
2662  {
2663  switch (true) {
2664  case !isset($this->currentCert) || !is_array($this->currentCert):
2665  break;
2666  case isset($this->currentCert['tbsCertificate']):
2667  return $this->getDNProp($propName, $this->currentCert['tbsCertificate']['issuer'], $withType);
2668  case isset($this->currentCert['tbsCertList']):
2669  return $this->getDNProp($propName, $this->currentCert['tbsCertList']['issuer'], $withType);
2670  }
2671 
2672  return false;
2673  }
2674 
2683  function getSubjectDNProp($propName, $withType = false)
2684  {
2685  switch (true) {
2686  case !empty($this->dn):
2687  return $this->getDNProp($propName, null, $withType);
2688  case !isset($this->currentCert) || !is_array($this->currentCert):
2689  break;
2690  case isset($this->currentCert['tbsCertificate']):
2691  return $this->getDNProp($propName, $this->currentCert['tbsCertificate']['subject'], $withType);
2692  case isset($this->currentCert['certificationRequestInfo']):
2693  return $this->getDNProp($propName, $this->currentCert['certificationRequestInfo']['subject'], $withType);
2694  }
2695 
2696  return false;
2697  }
2698 
2705  function getChain()
2706  {
2707  $chain = array($this->currentCert);
2708 
2709  if (!is_array($this->currentCert) || !isset($this->currentCert['tbsCertificate'])) {
2710  return false;
2711  }
2712  if (empty($this->CAs)) {
2713  return $chain;
2714  }
2715  while (true) {
2716  $currentCert = $chain[count($chain) - 1];
2717  for ($i = 0; $i < count($this->CAs); $i++) {
2718  $ca = $this->CAs[$i];
2719  if ($currentCert['tbsCertificate']['issuer'] === $ca['tbsCertificate']['subject']) {
2720  $authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier', $currentCert);
2721  $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca);
2722  switch (true) {
2723  case !is_array($authorityKey):
2724  case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
2725  if ($currentCert === $ca) {
2726  break 3;
2727  }
2728  $chain[] = $ca;
2729  break 2;
2730  }
2731  }
2732  }
2733  if ($i == count($this->CAs)) {
2734  break;
2735  }
2736  }
2737  foreach ($chain as $key => $value) {
2738  $chain[$key] = new X509();
2739  $chain[$key]->loadX509($value);
2740  }
2741  return $chain;
2742  }
2743 
2753  function setPublicKey($key)
2754  {
2755  $key->setPublicKey();
2756  $this->publicKey = $key;
2757  }
2758 
2768  {
2769  $this->privateKey = $key;
2770  }
2771 
2780  function setChallenge($challenge)
2781  {
2782  $this->challenge = $challenge;
2783  }
2784 
2793  function getPublicKey()
2794  {
2795  if (isset($this->publicKey)) {
2796  return $this->publicKey;
2797  }
2798 
2799  if (isset($this->currentCert) && is_array($this->currentCert)) {
2800  foreach (array('tbsCertificate/subjectPublicKeyInfo', 'certificationRequestInfo/subjectPKInfo') as $path) {
2801  $keyinfo = $this->_subArray($this->currentCert, $path);
2802  if (!empty($keyinfo)) {
2803  break;
2804  }
2805  }
2806  }
2807  if (empty($keyinfo)) {
2808  return false;
2809  }
2810 
2811  $key = $keyinfo['subjectPublicKey'];
2812 
2813  switch ($keyinfo['algorithm']['algorithm']) {
2814  case 'rsaEncryption':
2815  $publicKey = new RSA();
2816  $publicKey->loadKey($key);
2817  $publicKey->setPublicKey();
2818  break;
2819  default:
2820  return false;
2821  }
2822 
2823  return $publicKey;
2824  }
2825 
2833  function loadCSR($csr, $mode = self::FORMAT_AUTO_DETECT)
2834  {
2835  if (is_array($csr) && isset($csr['certificationRequestInfo'])) {
2836  unset($this->currentCert);
2837  unset($this->currentKeyIdentifier);
2838  unset($this->signatureSubject);
2839  $this->dn = $csr['certificationRequestInfo']['subject'];
2840  if (!isset($this->dn)) {
2841  return false;
2842  }
2843 
2844  $this->currentCert = $csr;
2845  return $csr;
2846  }
2847 
2848  // see http://tools.ietf.org/html/rfc2986
2849 
2850  $asn1 = new ASN1();
2851 
2852  if ($mode != self::FORMAT_DER) {
2853  $newcsr = $this->_extractBER($csr);
2854  if ($mode == self::FORMAT_PEM && $csr == $newcsr) {
2855  return false;
2856  }
2857  $csr = $newcsr;
2858  }
2859  $orig = $csr;
2860 
2861  if ($csr === false) {
2862  $this->currentCert = false;
2863  return false;
2864  }
2865 
2866  $asn1->loadOIDs($this->oids);
2867  $decoded = $asn1->decodeBER($csr);
2868 
2869  if (empty($decoded)) {
2870  $this->currentCert = false;
2871  return false;
2872  }
2873 
2874  $csr = $asn1->asn1map($decoded[0], $this->CertificationRequest);
2875  if (!isset($csr) || $csr === false) {
2876  $this->currentCert = false;
2877  return false;
2878  }
2879 
2880  $this->dn = $csr['certificationRequestInfo']['subject'];
2881  $this->_mapInAttributes($csr, 'certificationRequestInfo/attributes', $asn1);
2882 
2883  $this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);
2884 
2885  $algorithm = &$csr['certificationRequestInfo']['subjectPKInfo']['algorithm']['algorithm'];
2886  $key = &$csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'];
2887  $key = $this->_reformatKey($algorithm, $key);
2888 
2889  switch ($algorithm) {
2890  case 'rsaEncryption':
2891  $this->publicKey = new RSA();
2892  $this->publicKey->loadKey($key);
2893  $this->publicKey->setPublicKey();
2894  break;
2895  default:
2896  $this->publicKey = null;
2897  }
2898 
2899  $this->currentKeyIdentifier = null;
2900  $this->currentCert = $csr;
2901 
2902  return $csr;
2903  }
2904 
2913  function saveCSR($csr, $format = self::FORMAT_PEM)
2914  {
2915  if (!is_array($csr) || !isset($csr['certificationRequestInfo'])) {
2916  return false;
2917  }
2918 
2919  switch (true) {
2920  case !($algorithm = $this->_subArray($csr, 'certificationRequestInfo/subjectPKInfo/algorithm/algorithm')):
2921  case is_object($csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']):
2922  break;
2923  default:
2924  switch ($algorithm) {
2925  case 'rsaEncryption':
2926  $csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']
2927  = base64_encode("\0" . base64_decode(preg_replace('#-.+-|[\r\n]#', '', $csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'])));
2928  }
2929  }
2930 
2931  $asn1 = new ASN1();
2932 
2933  $asn1->loadOIDs($this->oids);
2934 
2935  $filters = array();
2936  $filters['certificationRequestInfo']['subject']['rdnSequence']['value']
2937  = array('type' => ASN1::TYPE_UTF8_STRING);
2938 
2939  $asn1->loadFilters($filters);
2940 
2941  $this->_mapOutAttributes($csr, 'certificationRequestInfo/attributes', $asn1);
2942  $csr = $asn1->encodeDER($csr, $this->CertificationRequest);
2943 
2944  switch ($format) {
2945  case self::FORMAT_DER:
2946  return $csr;
2947  // case self::FORMAT_PEM:
2948  default:
2949  return "-----BEGIN CERTIFICATE REQUEST-----\r\n" . chunk_split(base64_encode($csr), 64) . '-----END CERTIFICATE REQUEST-----';
2950  }
2951  }
2952 
2964  function loadSPKAC($spkac)
2965  {
2966  if (is_array($spkac) && isset($spkac['publicKeyAndChallenge'])) {
2967  unset($this->currentCert);
2968  unset($this->currentKeyIdentifier);
2969  unset($this->signatureSubject);
2970  $this->currentCert = $spkac;
2971  return $spkac;
2972  }
2973 
2974  // see http://www.w3.org/html/wg/drafts/html/master/forms.html#signedpublickeyandchallenge
2975 
2976  $asn1 = new ASN1();
2977 
2978  // OpenSSL produces SPKAC's that are preceeded by the string SPKAC=
2979  $temp = preg_replace('#(?:SPKAC=)|[ \r\n\\\]#', '', $spkac);
2980  $temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false;
2981  if ($temp != false) {
2982  $spkac = $temp;
2983  }
2984  $orig = $spkac;
2985 
2986  if ($spkac === false) {
2987  $this->currentCert = false;
2988  return false;
2989  }
2990 
2991  $asn1->loadOIDs($this->oids);
2992  $decoded = $asn1->decodeBER($spkac);
2993 
2994  if (empty($decoded)) {
2995  $this->currentCert = false;
2996  return false;
2997  }
2998 
2999  $spkac = $asn1->asn1map($decoded[0], $this->SignedPublicKeyAndChallenge);
3000 
3001  if (!isset($spkac) || $spkac === false) {
3002  $this->currentCert = false;
3003  return false;
3004  }
3005 
3006  $this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);
3007 
3008  $algorithm = &$spkac['publicKeyAndChallenge']['spki']['algorithm']['algorithm'];
3009  $key = &$spkac['publicKeyAndChallenge']['spki']['subjectPublicKey'];
3010  $key = $this->_reformatKey($algorithm, $key);
3011 
3012  switch ($algorithm) {
3013  case 'rsaEncryption':
3014  $this->publicKey = new RSA();
3015  $this->publicKey->loadKey($key);
3016  $this->publicKey->setPublicKey();
3017  break;
3018  default:
3019  $this->publicKey = null;
3020  }
3021 
3022  $this->currentKeyIdentifier = null;
3023  $this->currentCert = $spkac;
3024 
3025  return $spkac;
3026  }
3027 
3036  function saveSPKAC($spkac, $format = self::FORMAT_PEM)
3037  {
3038  if (!is_array($spkac) || !isset($spkac['publicKeyAndChallenge'])) {
3039  return false;
3040  }
3041 
3042  $algorithm = $this->_subArray($spkac, 'publicKeyAndChallenge/spki/algorithm/algorithm');
3043  switch (true) {
3044  case !$algorithm:
3045  case is_object($spkac['publicKeyAndChallenge']['spki']['subjectPublicKey']):
3046  break;
3047  default:
3048  switch ($algorithm) {
3049  case 'rsaEncryption':
3050  $spkac['publicKeyAndChallenge']['spki']['subjectPublicKey']
3051  = base64_encode("\0" . base64_decode(preg_replace('#-.+-|[\r\n]#', '', $spkac['publicKeyAndChallenge']['spki']['subjectPublicKey'])));
3052  }
3053  }
3054 
3055  $asn1 = new ASN1();
3056 
3057  $asn1->loadOIDs($this->oids);
3058  $spkac = $asn1->encodeDER($spkac, $this->SignedPublicKeyAndChallenge);
3059 
3060  switch ($format) {
3061  case self::FORMAT_DER:
3062  return $spkac;
3063  // case self::FORMAT_PEM:
3064  default:
3065  // OpenSSL's implementation of SPKAC requires the SPKAC be preceeded by SPKAC= and since there are pretty much
3066  // no other SPKAC decoders phpseclib will use that same format
3067  return 'SPKAC=' . base64_encode($spkac);
3068  }
3069  }
3070 
3078  function loadCRL($crl, $mode = self::FORMAT_AUTO_DETECT)
3079  {
3080  if (is_array($crl) && isset($crl['tbsCertList'])) {
3081  $this->currentCert = $crl;
3082  unset($this->signatureSubject);
3083  return $crl;
3084  }
3085 
3086  $asn1 = new ASN1();
3087 
3088  if ($mode != self::FORMAT_DER) {
3089  $newcrl = $this->_extractBER($crl);
3090  if ($mode == self::FORMAT_PEM && $crl == $newcrl) {
3091  return false;
3092  }
3093  $crl = $newcrl;
3094  }
3095  $orig = $crl;
3096 
3097  if ($crl === false) {
3098  $this->currentCert = false;
3099  return false;
3100  }
3101 
3102  $asn1->loadOIDs($this->oids);
3103  $decoded = $asn1->decodeBER($crl);
3104 
3105  if (empty($decoded)) {
3106  $this->currentCert = false;
3107  return false;
3108  }
3109 
3110  $crl = $asn1->asn1map($decoded[0], $this->CertificateList);
3111  if (!isset($crl) || $crl === false) {
3112  $this->currentCert = false;
3113  return false;
3114  }
3115 
3116  $this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);
3117 
3118  $this->_mapInExtensions($crl, 'tbsCertList/crlExtensions', $asn1);
3119  $rclist = &$this->_subArray($crl, 'tbsCertList/revokedCertificates');
3120  if (is_array($rclist)) {
3121  foreach ($rclist as $i => $extension) {
3122  $this->_mapInExtensions($rclist, "$i/crlEntryExtensions", $asn1);
3123  }
3124  }
3125 
3126  $this->currentKeyIdentifier = null;
3127  $this->currentCert = $crl;
3128 
3129  return $crl;
3130  }
3131 
3140  function saveCRL($crl, $format = self::FORMAT_PEM)
3141  {
3142  if (!is_array($crl) || !isset($crl['tbsCertList'])) {
3143  return false;
3144  }
3145 
3146  $asn1 = new ASN1();
3147 
3148  $asn1->loadOIDs($this->oids);
3149 
3150  $filters = array();
3151  $filters['tbsCertList']['issuer']['rdnSequence']['value']
3152  = array('type' => ASN1::TYPE_UTF8_STRING);
3153  $filters['tbsCertList']['signature']['parameters']
3154  = array('type' => ASN1::TYPE_UTF8_STRING);
3155  $filters['signatureAlgorithm']['parameters']
3156  = array('type' => ASN1::TYPE_UTF8_STRING);
3157 
3158  if (empty($crl['tbsCertList']['signature']['parameters'])) {
3159  $filters['tbsCertList']['signature']['parameters']
3160  = array('type' => ASN1::TYPE_NULL);
3161  }
3162 
3163  if (empty($crl['signatureAlgorithm']['parameters'])) {
3164  $filters['signatureAlgorithm']['parameters']
3165  = array('type' => ASN1::TYPE_NULL);
3166  }
3167 
3168  $asn1->loadFilters($filters);
3169 
3170  $this->_mapOutExtensions($crl, 'tbsCertList/crlExtensions', $asn1);
3171  $rclist = &$this->_subArray($crl, 'tbsCertList/revokedCertificates');
3172  if (is_array($rclist)) {
3173  foreach ($rclist as $i => $extension) {
3174  $this->_mapOutExtensions($rclist, "$i/crlEntryExtensions", $asn1);
3175  }
3176  }
3177 
3178  $crl = $asn1->encodeDER($crl, $this->CertificateList);
3179 
3180  switch ($format) {
3181  case self::FORMAT_DER:
3182  return $crl;
3183  // case self::FORMAT_PEM:
3184  default:
3185  return "-----BEGIN X509 CRL-----\r\n" . chunk_split(base64_encode($crl), 64) . '-----END X509 CRL-----';
3186  }
3187  }
3188 
3201  function _timeField($date)
3202  {
3203  $year = @gmdate("Y", @strtotime($date)); // the same way ASN1.php parses this
3204  if ($year < 2050) {
3205  return array('utcTime' => $date);
3206  } else {
3207  return array('generalTime' => $date);
3208  }
3209  }
3210 
3224  function sign($issuer, $subject, $signatureAlgorithm = 'sha1WithRSAEncryption')
3225  {
3226  if (!is_object($issuer->privateKey) || empty($issuer->dn)) {
3227  return false;
3228  }
3229 
3230  if (isset($subject->publicKey) && !($subjectPublicKey = $subject->_formatSubjectPublicKey())) {
3231  return false;
3232  }
3233 
3234  $currentCert = isset($this->currentCert) ? $this->currentCert : null;
3235  $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject: null;
3236 
3237  if (isset($subject->currentCert) && is_array($subject->currentCert) && isset($subject->currentCert['tbsCertificate'])) {
3238  $this->currentCert = $subject->currentCert;
3239  $this->currentCert['tbsCertificate']['signature']['algorithm'] = $signatureAlgorithm;
3240  $this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm;
3241 
3242  if (!empty($this->startDate)) {
3243  $this->currentCert['tbsCertificate']['validity']['notBefore'] = $this->_timeField($this->startDate);
3244  }
3245  if (!empty($this->endDate)) {
3246  $this->currentCert['tbsCertificate']['validity']['notAfter'] = $this->_timeField($this->endDate);
3247  }
3248  if (!empty($this->serialNumber)) {
3249  $this->currentCert['tbsCertificate']['serialNumber'] = $this->serialNumber;
3250  }
3251  if (!empty($subject->dn)) {
3252  $this->currentCert['tbsCertificate']['subject'] = $subject->dn;
3253  }
3254  if (!empty($subject->publicKey)) {
3255  $this->currentCert['tbsCertificate']['subjectPublicKeyInfo'] = $subjectPublicKey;
3256  }
3257  $this->removeExtension('id-ce-authorityKeyIdentifier');
3258  if (isset($subject->domains)) {
3259  $this->removeExtension('id-ce-subjectAltName');
3260  }
3261  } elseif (isset($subject->currentCert) && is_array($subject->currentCert) && isset($subject->currentCert['tbsCertList'])) {
3262  return false;
3263  } else {
3264  if (!isset($subject->publicKey)) {
3265  return false;
3266  }
3267 
3268  $startDate = !empty($this->startDate) ? $this->startDate : @date('D, d M Y H:i:s O');
3269  $endDate = !empty($this->endDate) ? $this->endDate : @date('D, d M Y H:i:s O', strtotime('+1 year'));
3270  /* "The serial number MUST be a positive integer"
3271  "Conforming CAs MUST NOT use serialNumber values longer than 20 octets."
3272  -- https://tools.ietf.org/html/rfc5280#section-4.1.2.2
3273 
3274  for the integer to be positive the leading bit needs to be 0 hence the
3275  application of a bitmap
3276  */
3277  $serialNumber = !empty($this->serialNumber) ?
3278  $this->serialNumber :
3279  new BigInteger(Random::string(20) & ("\x7F" . str_repeat("\xFF", 19)), 256);
3280 
3281  $this->currentCert = array(
3282  'tbsCertificate' =>
3283  array(
3284  'version' => 'v3',
3285  'serialNumber' => $serialNumber, // $this->setserialNumber()
3286  'signature' => array('algorithm' => $signatureAlgorithm),
3287  'issuer' => false, // this is going to be overwritten later
3288  'validity' => array(
3289  'notBefore' => $this->_timeField($startDate), // $this->setStartDate()
3290  'notAfter' => $this->_timeField($endDate) // $this->setEndDate()
3291  ),
3292  'subject' => $subject->dn,
3293  'subjectPublicKeyInfo' => $subjectPublicKey
3294  ),
3295  'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm),
3296  'signature' => false // this is going to be overwritten later
3297  );
3298 
3299  // Copy extensions from CSR.
3300  $csrexts = $subject->getAttribute('pkcs-9-at-extensionRequest', 0);
3301 
3302  if (!empty($csrexts)) {
3303  $this->currentCert['tbsCertificate']['extensions'] = $csrexts;
3304  }
3305  }
3306 
3307  $this->currentCert['tbsCertificate']['issuer'] = $issuer->dn;
3308 
3309  if (isset($issuer->currentKeyIdentifier)) {
3310  $this->setExtension('id-ce-authorityKeyIdentifier', array(
3311  //'authorityCertIssuer' => array(
3312  // array(
3313  // 'directoryName' => $issuer->dn
3314  // )
3315  //),
3316  'keyIdentifier' => $issuer->currentKeyIdentifier
3317  ));
3318  //$extensions = &$this->currentCert['tbsCertificate']['extensions'];
3319  //if (isset($issuer->serialNumber)) {
3320  // $extensions[count($extensions) - 1]['authorityCertSerialNumber'] = $issuer->serialNumber;
3321  //}
3322  //unset($extensions);
3323  }
3324 
3325  if (isset($subject->currentKeyIdentifier)) {
3326  $this->setExtension('id-ce-subjectKeyIdentifier', $subject->currentKeyIdentifier);
3327  }
3328 
3329  $altName = array();
3330 
3331  if (isset($subject->domains) && count($subject->domains) > 1) {
3332  $altName = array_map(array('X509', '_dnsName'), $subject->domains);
3333  }
3334 
3335  if (isset($subject->ipAddresses) && count($subject->ipAddresses)) {
3336  // should an IP address appear as the CN if no domain name is specified? idk
3337  //$ips = count($subject->domains) ? $subject->ipAddresses : array_slice($subject->ipAddresses, 1);
3338  $ipAddresses = array();
3339  foreach ($subject->ipAddresses as $ipAddress) {
3340  $encoded = $subject->_ipAddress($ipAddress);
3341  if ($encoded !== false) {
3342  $ipAddresses[] = $encoded;
3343  }
3344  }
3345  if (count($ipAddresses)) {
3346  $altName = array_merge($altName, $ipAddresses);
3347  }
3348  }
3349 
3350  if (!empty($altName)) {
3351  $this->setExtension('id-ce-subjectAltName', $altName);
3352  }
3353 
3354  if ($this->caFlag) {
3355  $keyUsage = $this->getExtension('id-ce-keyUsage');
3356  if (!$keyUsage) {
3357  $keyUsage = array();
3358  }
3359 
3360  $this->setExtension(
3361  'id-ce-keyUsage',
3362  array_values(array_unique(array_merge($keyUsage, array('cRLSign', 'keyCertSign'))))
3363  );
3364 
3365  $basicConstraints = $this->getExtension('id-ce-basicConstraints');
3366  if (!$basicConstraints) {
3367  $basicConstraints = array();
3368  }
3369 
3370  $this->setExtension(
3371  'id-ce-basicConstraints',
3372  array_unique(array_merge(array('cA' => true), $basicConstraints)),
3373  true
3374  );
3375 
3376  if (!isset($subject->currentKeyIdentifier)) {
3377  $this->setExtension('id-ce-subjectKeyIdentifier', base64_encode($this->computeKeyIdentifier($this->currentCert)), false, false);
3378  }
3379  }
3380 
3381  // resync $this->signatureSubject
3382  // save $tbsCertificate in case there are any \phpseclib\File\ASN1\Element objects in it
3383  $tbsCertificate = $this->currentCert['tbsCertificate'];
3384  $this->loadX509($this->saveX509($this->currentCert));
3385 
3386  $result = $this->_sign($issuer->privateKey, $signatureAlgorithm);
3387  $result['tbsCertificate'] = $tbsCertificate;
3388 
3389  $this->currentCert = $currentCert;
3390  $this->signatureSubject = $signatureSubject;
3391 
3392  return $result;
3393  }
3394 
3401  function signCSR($signatureAlgorithm = 'sha1WithRSAEncryption')
3402  {
3403  if (!is_object($this->privateKey) || empty($this->dn)) {
3404  return false;
3405  }
3406 
3407  $origPublicKey = $this->publicKey;
3408  $class = get_class($this->privateKey);
3409  $this->publicKey = new $class();
3410  $this->publicKey->loadKey($this->privateKey->getPublicKey());
3411  $this->publicKey->setPublicKey();
3412  if (!($publicKey = $this->_formatSubjectPublicKey())) {
3413  return false;
3414  }
3415  $this->publicKey = $origPublicKey;
3416 
3417  $currentCert = isset($this->currentCert) ? $this->currentCert : null;
3418  $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject: null;
3419 
3420  if (isset($this->currentCert) && is_array($this->currentCert) && isset($this->currentCert['certificationRequestInfo'])) {
3421  $this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm;
3422  if (!empty($this->dn)) {
3423  $this->currentCert['certificationRequestInfo']['subject'] = $this->dn;
3424  }
3425  $this->currentCert['certificationRequestInfo']['subjectPKInfo'] = $publicKey;
3426  } else {
3427  $this->currentCert = array(
3428  'certificationRequestInfo' =>
3429  array(
3430  'version' => 'v1',
3431  'subject' => $this->dn,
3432  'subjectPKInfo' => $publicKey
3433  ),
3434  'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm),
3435  'signature' => false // this is going to be overwritten later
3436  );
3437  }
3438 
3439  // resync $this->signatureSubject
3440  // save $certificationRequestInfo in case there are any \phpseclib\File\ASN1\Element objects in it
3441  $certificationRequestInfo = $this->currentCert['certificationRequestInfo'];
3442  $this->loadCSR($this->saveCSR($this->currentCert));
3443 
3444  $result = $this->_sign($this->privateKey, $signatureAlgorithm);
3445  $result['certificationRequestInfo'] = $certificationRequestInfo;
3446 
3447  $this->currentCert = $currentCert;
3448  $this->signatureSubject = $signatureSubject;
3449 
3450  return $result;
3451  }
3452 
3459  function signSPKAC($signatureAlgorithm = 'sha1WithRSAEncryption')
3460  {
3461  if (!is_object($this->privateKey)) {
3462  return false;
3463  }
3464 
3465  $origPublicKey = $this->publicKey;
3466  $class = get_class($this->privateKey);
3467  $this->publicKey = new $class();
3468  $this->publicKey->loadKey($this->privateKey->getPublicKey());
3469  $this->publicKey->setPublicKey();
3470  $publicKey = $this->_formatSubjectPublicKey();
3471  if (!$publicKey) {
3472  return false;
3473  }
3474  $this->publicKey = $origPublicKey;
3475 
3476  $currentCert = isset($this->currentCert) ? $this->currentCert : null;
3477  $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject: null;
3478 
3479  // re-signing a SPKAC seems silly but since everything else supports re-signing why not?
3480  if (isset($this->currentCert) && is_array($this->currentCert) && isset($this->currentCert['publicKeyAndChallenge'])) {
3481  $this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm;
3482  $this->currentCert['publicKeyAndChallenge']['spki'] = $publicKey;
3483  if (!empty($this->challenge)) {
3484  // the bitwise AND ensures that the output is a valid IA5String
3485  $this->currentCert['publicKeyAndChallenge']['challenge'] = $this->challenge & str_repeat("\x7F", strlen($this->challenge));
3486  }
3487  } else {
3488  $this->currentCert = array(
3489  'publicKeyAndChallenge' =>
3490  array(
3491  'spki' => $publicKey,
3492  // quoting <https://developer.mozilla.org/en-US/docs/Web/HTML/Element/keygen>,
3493  // "A challenge string that is submitted along with the public key. Defaults to an empty string if not specified."
3494  // both Firefox and OpenSSL ("openssl spkac -key private.key") behave this way
3495  // we could alternatively do this instead if we ignored the specs:
3496  // Random::string(8) & str_repeat("\x7F", 8)
3497  'challenge' => !empty($this->challenge) ? $this->challenge : ''
3498  ),
3499  'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm),
3500  'signature' => false // this is going to be overwritten later
3501  );
3502  }
3503 
3504  // resync $this->signatureSubject
3505  // save $publicKeyAndChallenge in case there are any \phpseclib\File\ASN1\Element objects in it
3506  $publicKeyAndChallenge = $this->currentCert['publicKeyAndChallenge'];
3507  $this->loadSPKAC($this->saveSPKAC($this->currentCert));
3508 
3509  $result = $this->_sign($this->privateKey, $signatureAlgorithm);
3510  $result['publicKeyAndChallenge'] = $publicKeyAndChallenge;
3511 
3512  $this->currentCert = $currentCert;
3513  $this->signatureSubject = $signatureSubject;
3514 
3515  return $result;
3516  }
3517 
3529  function signCRL($issuer, $crl, $signatureAlgorithm = 'sha1WithRSAEncryption')
3530  {
3531  if (!is_object($issuer->privateKey) || empty($issuer->dn)) {
3532  return false;
3533  }
3534 
3535  $currentCert = isset($this->currentCert) ? $this->currentCert : null;
3536  $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject : null;
3537  $thisUpdate = !empty($this->startDate) ? $this->startDate : @date('D, d M Y H:i:s O');
3538 
3539  if (isset($crl->currentCert) && is_array($crl->currentCert) && isset($crl->currentCert['tbsCertList'])) {
3540  $this->currentCert = $crl->currentCert;
3541  $this->currentCert['tbsCertList']['signature']['algorithm'] = $signatureAlgorithm;
3542  $this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm;
3543  } else {
3544  $this->currentCert = array(
3545  'tbsCertList' =>
3546  array(
3547  'version' => 'v2',
3548  'signature' => array('algorithm' => $signatureAlgorithm),
3549  'issuer' => false, // this is going to be overwritten later
3550  'thisUpdate' => $this->_timeField($thisUpdate) // $this->setStartDate()
3551  ),
3552  'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm),
3553  'signature' => false // this is going to be overwritten later
3554  );
3555  }
3556 
3557  $tbsCertList = &$this->currentCert['tbsCertList'];
3558  $tbsCertList['issuer'] = $issuer->dn;
3559  $tbsCertList['thisUpdate'] = $this->_timeField($thisUpdate);
3560 
3561  if (!empty($this->endDate)) {
3562  $tbsCertList['nextUpdate'] = $this->_timeField($this->endDate); // $this->setEndDate()
3563  } else {
3564  unset($tbsCertList['nextUpdate']);
3565  }
3566 
3567  if (!empty($this->serialNumber)) {
3568  $crlNumber = $this->serialNumber;
3569  } else {
3570  $crlNumber = $this->getExtension('id-ce-cRLNumber');
3571  // "The CRL number is a non-critical CRL extension that conveys a
3572  // monotonically increasing sequence number for a given CRL scope and
3573  // CRL issuer. This extension allows users to easily determine when a
3574  // particular CRL supersedes another CRL."
3575  // -- https://tools.ietf.org/html/rfc5280#section-5.2.3
3576  $crlNumber = $crlNumber !== false ? $crlNumber->add(new BigInteger(1)) : null;
3577  }
3578 
3579  $this->removeExtension('id-ce-authorityKeyIdentifier');
3580  $this->removeExtension('id-ce-issuerAltName');
3581 
3582  // Be sure version >= v2 if some extension found.
3583  $version = isset($tbsCertList['version']) ? $tbsCertList['version'] : 0;
3584  if (!$version) {
3585  if (!empty($tbsCertList['crlExtensions'])) {
3586  $version = 1; // v2.
3587  } elseif (!empty($tbsCertList['revokedCertificates'])) {
3588  foreach ($tbsCertList['revokedCertificates'] as $cert) {
3589  if (!empty($cert['crlEntryExtensions'])) {
3590  $version = 1; // v2.
3591  }
3592  }
3593  }
3594 
3595  if ($version) {
3596  $tbsCertList['version'] = $version;
3597  }
3598  }
3599 
3600  // Store additional extensions.
3601  if (!empty($tbsCertList['version'])) { // At least v2.
3602  if (!empty($crlNumber)) {
3603  $this->setExtension('id-ce-cRLNumber', $crlNumber);
3604  }
3605 
3606  if (isset($issuer->currentKeyIdentifier)) {
3607  $this->setExtension('id-ce-authorityKeyIdentifier', array(
3608  //'authorityCertIssuer' => array(
3609  // array(
3610  // 'directoryName' => $issuer->dn
3611  // )
3612  //),
3613  'keyIdentifier' => $issuer->currentKeyIdentifier
3614  ));
3615  //$extensions = &$tbsCertList['crlExtensions'];
3616  //if (isset($issuer->serialNumber)) {
3617  // $extensions[count($extensions) - 1]['authorityCertSerialNumber'] = $issuer->serialNumber;
3618  //}
3619  //unset($extensions);
3620  }
3621 
3622  $issuerAltName = $this->getExtension('id-ce-subjectAltName', $issuer->currentCert);
3623 
3624  if ($issuerAltName !== false) {
3625  $this->setExtension('id-ce-issuerAltName', $issuerAltName);
3626  }
3627  }
3628 
3629  if (empty($tbsCertList['revokedCertificates'])) {
3630  unset($tbsCertList['revokedCertificates']);
3631  }
3632 
3633  unset($tbsCertList);
3634 
3635  // resync $this->signatureSubject
3636  // save $tbsCertList in case there are any \phpseclib\File\ASN1\Element objects in it
3637  $tbsCertList = $this->currentCert['tbsCertList'];
3638  $this->loadCRL($this->saveCRL($this->currentCert));
3639 
3640  $result = $this->_sign($issuer->privateKey, $signatureAlgorithm);
3641  $result['tbsCertList'] = $tbsCertList;
3642 
3643  $this->currentCert = $currentCert;
3644  $this->signatureSubject = $signatureSubject;
3645 
3646  return $result;
3647  }
3648 
3658  function _sign($key, $signatureAlgorithm)
3659  {
3660  if ($key instanceof RSA) {
3661  switch ($signatureAlgorithm) {
3662  case 'md2WithRSAEncryption':
3663  case 'md5WithRSAEncryption':
3664  case 'sha1WithRSAEncryption':
3665  case 'sha224WithRSAEncryption':
3666  case 'sha256WithRSAEncryption':
3667  case 'sha384WithRSAEncryption':
3668  case 'sha512WithRSAEncryption':
3669  $key->setHash(preg_replace('#WithRSAEncryption$#', '', $signatureAlgorithm));
3670  $key->setSignatureMode(RSA::SIGNATURE_PKCS1);
3671 
3672  $this->currentCert['signature'] = base64_encode("\0" . $key->sign($this->signatureSubject));
3673  return $this->currentCert;
3674  }
3675  }
3676 
3677  return false;
3678  }
3679 
3686  function setStartDate($date)
3687  {
3688  $this->startDate = @date('D, d M Y H:i:s O', @strtotime($date));
3689  }
3690 
3697  function setEndDate($date)
3698  {
3699  /*
3700  To indicate that a certificate has no well-defined expiration date,
3701  the notAfter SHOULD be assigned the GeneralizedTime value of
3702  99991231235959Z.
3703 
3704  -- http://tools.ietf.org/html/rfc5280#section-4.1.2.5
3705  */
3706  if (strtolower($date) == 'lifetime') {
3707  $temp = '99991231235959Z';
3708  $asn1 = new ASN1();
3709  $temp = chr(ASN1::TYPE_GENERALIZED_TIME) . $asn1->_encodeLength(strlen($temp)) . $temp;
3710  $this->endDate = new Element($temp);
3711  } else {
3712  $this->endDate = @date('D, d M Y H:i:s O', @strtotime($date));
3713  }
3714  }
3715 
3723  function setSerialNumber($serial, $base = -256)
3724  {
3725  $this->serialNumber = new BigInteger($serial, $base);
3726  }
3727 
3733  function makeCA()
3734  {
3735  $this->caFlag = true;
3736  }
3737 
3747  function &_subArray(&$root, $path, $create = false)
3748  {
3749  $false = false;
3750 
3751  if (!is_array($root)) {
3752  return $false;
3753  }
3754 
3755  foreach (explode('/', $path) as $i) {
3756  if (!is_array($root)) {
3757  return $false;
3758  }
3759 
3760  if (!isset($root[$i])) {
3761  if (!$create) {
3762  return $false;
3763  }
3764 
3765  $root[$i] = array();
3766  }
3767 
3768  $root = &$root[$i];
3769  }
3770 
3771  return $root;
3772  }
3773 
3783  function &_extensions(&$root, $path = null, $create = false)
3784  {
3785  if (!isset($root)) {
3787  }
3788 
3789  switch (true) {
3790  case !empty($path):
3791  case !is_array($root):
3792  break;
3793  case isset($root['tbsCertificate']):
3794  $path = 'tbsCertificate/extensions';
3795  break;
3796  case isset($root['tbsCertList']):
3797  $path = 'tbsCertList/crlExtensions';
3798  break;
3799  case isset($root['certificationRequestInfo']):
3800  $pth = 'certificationRequestInfo/attributes';
3801  $attributes = &$this->_subArray($root, $pth, $create);
3802 
3803  if (is_array($attributes)) {
3804  foreach ($attributes as $key => $value) {
3805  if ($value['type'] == 'pkcs-9-at-extensionRequest') {
3806  $path = "$pth/$key/value/0";
3807  break 2;
3808  }
3809  }
3810  if ($create) {
3811  $key = count($attributes);
3812  $attributes[] = array('type' => 'pkcs-9-at-extensionRequest', 'value' => array());
3813  $path = "$pth/$key/value/0";
3814  }
3815  }
3816  break;
3817  }
3818 
3819  $extensions = &$this->_subArray($root, $path, $create);
3820 
3821  if (!is_array($extensions)) {
3822  $false = false;
3823  return $false;
3824  }
3825 
3826  return $extensions;
3827  }
3828 
3837  function _removeExtension($id, $path = null)
3838  {
3839  $extensions = &$this->_extensions($this->currentCert, $path);
3840 
3841  if (!is_array($extensions)) {
3842  return false;
3843  }
3844 
3845  $result = false;
3846  foreach ($extensions as $key => $value) {
3847  if ($value['extnId'] == $id) {
3848  unset($extensions[$key]);
3849  $result = true;
3850  }
3851  }
3852 
3853  $extensions = array_values($extensions);
3854  return $result;
3855  }
3856 
3868  function _getExtension($id, $cert = null, $path = null)
3869  {
3870  $extensions = $this->_extensions($cert, $path);
3871 
3872  if (!is_array($extensions)) {
3873  return false;
3874  }
3875 
3876  foreach ($extensions as $key => $value) {
3877  if ($value['extnId'] == $id) {
3878  return $value['extnValue'];
3879  }
3880  }
3881 
3882  return false;
3883  }
3884 
3893  function _getExtensions($cert = null, $path = null)
3894  {
3895  $exts = $this->_extensions($cert, $path);
3896  $extensions = array();
3897 
3898  if (is_array($exts)) {
3899  foreach ($exts as $extension) {
3900  $extensions[] = $extension['extnId'];
3901  }
3902  }
3903 
3904  return $extensions;
3905  }
3906 
3918  function _setExtension($id, $value, $critical = false, $replace = true, $path = null)
3919  {
3920  $extensions = &$this->_extensions($this->currentCert, $path, true);
3921 
3922  if (!is_array($extensions)) {
3923  return false;
3924  }
3925 
3926  $newext = array('extnId' => $id, 'critical' => $critical, 'extnValue' => $value);
3927 
3928  foreach ($extensions as $key => $value) {
3929  if ($value['extnId'] == $id) {
3930  if (!$replace) {
3931  return false;
3932  }
3933 
3934  $extensions[$key] = $newext;
3935  return true;
3936  }
3937  }
3938 
3939  $extensions[] = $newext;
3940  return true;
3941  }
3942 
3951  {
3952  return $this->_removeExtension($id);
3953  }
3954 
3965  function getExtension($id, $cert = null)
3966  {
3967  return $this->_getExtension($id, $cert);
3968  }
3969 
3977  function getExtensions($cert = null)
3978  {
3979  return $this->_getExtensions($cert);
3980  }
3981 
3992  function setExtension($id, $value, $critical = false, $replace = true)
3993  {
3994  return $this->_setExtension($id, $value, $critical, $replace);
3995  }
3996 
4005  function removeAttribute($id, $disposition = self::ATTR_ALL)
4006  {
4007  $attributes = &$this->_subArray($this->currentCert, 'certificationRequestInfo/attributes');
4008 
4009  if (!is_array($attributes)) {
4010  return false;
4011  }
4012 
4013  $result = false;
4014  foreach ($attributes as $key => $attribute) {
4015  if ($attribute['type'] == $id) {
4016  $n = count($attribute['value']);
4017  switch (true) {
4018  case $disposition == self::ATTR_APPEND:
4019  case $disposition == self::ATTR_REPLACE:
4020  return false;
4021  case $disposition >= $n:
4022  $disposition -= $n;
4023  break;
4024  case $disposition == self::ATTR_ALL:
4025  case $n == 1:
4026  unset($attributes[$key]);
4027  $result = true;
4028  break;
4029  default:
4030  unset($attributes[$key]['value'][$disposition]);
4031  $attributes[$key]['value'] = array_values($attributes[$key]['value']);
4032  $result = true;
4033  break;
4034  }
4035  if ($result && $disposition != self::ATTR_ALL) {
4036  break;
4037  }
4038  }
4039  }
4040 
4041  $attributes = array_values($attributes);
4042  return $result;
4043  }
4044 
4056  function getAttribute($id, $disposition = self::ATTR_ALL, $csr = null)
4057  {
4058  if (empty($csr)) {
4059  $csr = $this->currentCert;
4060  }
4061 
4062  $attributes = $this->_subArray($csr, 'certificationRequestInfo/attributes');
4063 
4064  if (!is_array($attributes)) {
4065  return false;
4066  }
4067 
4068  foreach ($attributes as $key => $attribute) {
4069  if ($attribute['type'] == $id) {
4070  $n = count($attribute['value']);
4071  switch (true) {
4072  case $disposition == self::ATTR_APPEND:
4073  case $disposition == self::ATTR_REPLACE:
4074  return false;
4075  case $disposition == self::ATTR_ALL:
4076  return $attribute['value'];
4077  case $disposition >= $n:
4078  $disposition -= $n;
4079  break;
4080  default:
4081  return $attribute['value'][$disposition];
4082  }
4083  }
4084  }
4085 
4086  return false;
4087  }
4088 
4096  function getAttributes($csr = null)
4097  {
4098  if (empty($csr)) {
4099  $csr = $this->currentCert;
4100  }
4101 
4102  $attributes = $this->_subArray($csr, 'certificationRequestInfo/attributes');
4103  $attrs = array();
4104 
4105  if (is_array($attributes)) {
4106  foreach ($attributes as $attribute) {
4107  $attrs[] = $attribute['type'];
4108  }
4109  }
4110 
4111  return $attrs;
4112  }
4113 
4123  function setAttribute($id, $value, $disposition = self::ATTR_ALL)
4124  {
4125  $attributes = &$this->_subArray($this->currentCert, 'certificationRequestInfo/attributes', true);
4126 
4127  if (!is_array($attributes)) {
4128  return false;
4129  }
4130 
4131  switch ($disposition) {
4132  case self::ATTR_REPLACE:
4133  $disposition = self::ATTR_APPEND;
4134  case self::ATTR_ALL:
4135  $this->removeAttribute($id);
4136  break;
4137  }
4138 
4139  foreach ($attributes as $key => $attribute) {
4140  if ($attribute['type'] == $id) {
4141  $n = count($attribute['value']);
4142  switch (true) {
4143  case $disposition == self::ATTR_APPEND:
4144  $last = $key;
4145  break;
4146  case $disposition >= $n:
4147  $disposition -= $n;
4148  break;
4149  default:
4150  $attributes[$key]['value'][$disposition] = $value;
4151  return true;
4152  }
4153  }
4154  }
4155 
4156  switch (true) {
4157  case $disposition >= 0:
4158  return false;
4159  case isset($last):
4160  $attributes[$last]['value'][] = $value;
4161  break;
4162  default:
4163  $attributes[] = array('type' => $id, 'value' => $disposition == self::ATTR_ALL ? $value: array($value));
4164  break;
4165  }
4166 
4167  return true;
4168  }
4169 
4178  function setKeyIdentifier($value)
4179  {
4180  if (empty($value)) {
4181  unset($this->currentKeyIdentifier);
4182  } else {
4183  $this->currentKeyIdentifier = base64_encode($value);
4184  }
4185  }
4186 
4205  function computeKeyIdentifier($key = null, $method = 1)
4206  {
4207  if (is_null($key)) {
4208  $key = $this;
4209  }
4210 
4211  switch (true) {
4212  case is_string($key):
4213  break;
4214  case is_array($key) && isset($key['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']):
4215  return $this->computeKeyIdentifier($key['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'], $method);
4216  case is_array($key) && isset($key['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']):
4217  return $this->computeKeyIdentifier($key['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'], $method);
4218  case !is_object($key):
4219  return false;
4220  case $key instanceof Element:
4221  // Assume the element is a bitstring-packed key.
4222  $asn1 = new ASN1();
4223  $decoded = $asn1->decodeBER($key->element);
4224  if (empty($decoded)) {
4225  return false;
4226  }
4227  $raw = $asn1->asn1map($decoded[0], array('type' => ASN1::TYPE_BIT_STRING));
4228  if (empty($raw)) {
4229  return false;
4230  }
4231  $raw = base64_decode($raw);
4232  // If the key is private, compute identifier from its corresponding public key.
4233  $key = new RSA();
4234  if (!$key->loadKey($raw)) {
4235  return false; // Not an unencrypted RSA key.
4236  }
4237  if ($key->getPrivateKey() !== false) { // If private.
4238  return $this->computeKeyIdentifier($key, $method);
4239  }
4240  $key = $raw; // Is a public key.
4241  break;
4242  case $key instanceof X509:
4243  if (isset($key->publicKey)) {
4244  return $this->computeKeyIdentifier($key->publicKey, $method);
4245  }
4246  if (isset($key->privateKey)) {
4247  return $this->computeKeyIdentifier($key->privateKey, $method);
4248  }
4249  if (isset($key->currentCert['tbsCertificate']) || isset($key->currentCert['certificationRequestInfo'])) {
4250  return $this->computeKeyIdentifier($key->currentCert, $method);
4251  }
4252  return false;
4253  default: // Should be a key object (i.e.: \phpseclib\Crypt\RSA).
4254  $key = $key->getPublicKey(RSA::PUBLIC_FORMAT_PKCS1);
4255  break;
4256  }
4257 
4258  // If in PEM format, convert to binary.
4259  $key = $this->_extractBER($key);
4260 
4261  // Now we have the key string: compute its sha-1 sum.
4262  $hash = new Hash('sha1');
4263  $hash = $hash->hash($key);
4264 
4265  if ($method == 2) {
4266  $hash = substr($hash, -8);
4267  $hash[0] = chr((ord($hash[0]) & 0x0F) | 0x40);
4268  }
4269 
4270  return $hash;
4271  }
4272 
4280  {
4281  if ($this->publicKey instanceof RSA) {
4282  // the following two return statements do the same thing. i dunno.. i just prefer the later for some reason.
4283  // the former is a good example of how to do fuzzing on the public key
4284  //return new Element(base64_decode(preg_replace('#-.+-|[\r\n]#', '', $this->publicKey->getPublicKey())));
4285  return array(
4286  'algorithm' => array('algorithm' => 'rsaEncryption'),
4287  'subjectPublicKey' => $this->publicKey->getPublicKey(RSA::PUBLIC_FORMAT_PKCS1)
4288  );
4289  }
4290 
4291  return false;
4292  }
4293 
4300  function setDomain()
4301  {
4302  $this->domains = func_get_args();
4303  $this->removeDNProp('id-at-commonName');
4304  $this->setDNProp('id-at-commonName', $this->domains[0]);
4305  }
4306 
4313  function setIPAddress()
4314  {
4315  $this->ipAddresses = func_get_args();
4316  /*
4317  if (!isset($this->domains)) {
4318  $this->removeDNProp('id-at-commonName');
4319  $this->setDNProp('id-at-commonName', $this->ipAddresses[0]);
4320  }
4321  */
4322  }
4323 
4331  function _dnsName($domain)
4332  {
4333  return array('dNSName' => $domain);
4334  }
4335 
4345  function _iPAddress($address)
4346  {
4347  return array('iPAddress' => $address);
4348  }
4349 
4359  function _revokedCertificate(&$rclist, $serial, $create = false)
4360  {
4361  $serial = new BigInteger($serial);
4362 
4363  foreach ($rclist as $i => $rc) {
4364  if (!($serial->compare($rc['userCertificate']))) {
4365  return $i;
4366  }
4367  }
4368 
4369  if (!$create) {
4370  return false;
4371  }
4372 
4373  $i = count($rclist);
4374  $rclist[] = array('userCertificate' => $serial,
4375  'revocationDate' => $this->_timeField(@date('D, d M Y H:i:s O')));
4376  return $i;
4377  }
4378 
4387  function revoke($serial, $date = null)
4388  {
4389  if (isset($this->currentCert['tbsCertList'])) {
4390  if (is_array($rclist = &$this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates', true))) {
4391  if ($this->_revokedCertificate($rclist, $serial) === false) { // If not yet revoked
4392  if (($i = $this->_revokedCertificate($rclist, $serial, true)) !== false) {
4393  if (!empty($date)) {
4394  $rclist[$i]['revocationDate'] = $this->_timeField($date);
4395  }
4396 
4397  return true;
4398  }
4399  }
4400  }
4401  }
4402 
4403  return false;
4404  }
4405 
4413  function unrevoke($serial)
4414  {
4415  if (is_array($rclist = &$this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates'))) {
4416  if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) {
4417  unset($rclist[$i]);
4418  $rclist = array_values($rclist);
4419  return true;
4420  }
4421  }
4422 
4423  return false;
4424  }
4425 
4433  function getRevoked($serial)
4434  {
4435  if (is_array($rclist = $this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates'))) {
4436  if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) {
4437  return $rclist[$i];
4438  }
4439  }
4440 
4441  return false;
4442  }
4443 
4451  function listRevoked($crl = null)
4452  {
4453  if (!isset($crl)) {
4454  $crl = $this->currentCert;
4455  }
4456 
4457  if (!isset($crl['tbsCertList'])) {
4458  return false;
4459  }
4460 
4461  $result = array();
4462 
4463  if (is_array($rclist = $this->_subArray($crl, 'tbsCertList/revokedCertificates'))) {
4464  foreach ($rclist as $rc) {
4465  $result[] = $rc['userCertificate']->toString();
4466  }
4467  }
4468 
4469  return $result;
4470  }
4471 
4481  {
4482  if (is_array($rclist = &$this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates'))) {
4483  if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) {
4484  return $this->_removeExtension($id, "tbsCertList/revokedCertificates/$i/crlEntryExtensions");
4485  }
4486  }
4487 
4488  return false;
4489  }
4490 
4502  function getRevokedCertificateExtension($serial, $id, $crl = null)
4503  {
4504  if (!isset($crl)) {
4505  $crl = $this->currentCert;
4506  }
4507 
4508  if (is_array($rclist = $this->_subArray($crl, 'tbsCertList/revokedCertificates'))) {
4509  if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) {
4510  return $this->_getExtension($id, $crl, "tbsCertList/revokedCertificates/$i/crlEntryExtensions");
4511  }
4512  }
4513 
4514  return false;
4515  }
4516 
4525  function getRevokedCertificateExtensions($serial, $crl = null)
4526  {
4527  if (!isset($crl)) {
4528  $crl = $this->currentCert;
4529  }
4530 
4531  if (is_array($rclist = $this->_subArray($crl, 'tbsCertList/revokedCertificates'))) {
4532  if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) {
4533  return $this->_getExtensions($crl, "tbsCertList/revokedCertificates/$i/crlEntryExtensions");
4534  }
4535  }
4536 
4537  return false;
4538  }
4539 
4551  function setRevokedCertificateExtension($serial, $id, $value, $critical = false, $replace = true)
4552  {
4553  if (isset($this->currentCert['tbsCertList'])) {
4554  if (is_array($rclist = &$this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates', true))) {
4555  if (($i = $this->_revokedCertificate($rclist, $serial, true)) !== false) {
4556  return $this->_setExtension($id, $value, $critical, $replace, "tbsCertList/revokedCertificates/$i/crlEntryExtensions");
4557  }
4558  }
4559  }
4560 
4561  return false;
4562  }
4563 
4571  function _extractBER($str)
4572  {
4573  /* X.509 certs are assumed to be base64 encoded but sometimes they'll have additional things in them
4574  * above and beyond the ceritificate.
4575  * ie. some may have the following preceding the -----BEGIN CERTIFICATE----- line:
4576  *
4577  * Bag Attributes
4578  * localKeyID: 01 00 00 00
4579  * subject=/O=organization/OU=org unit/CN=common name
4580  * issuer=/O=organization/CN=common name
4581  */
4582  $temp = preg_replace('#.*?^-+[^-]+-+[\r\n ]*$#ms', '', $str, 1);
4583  // remove the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- stuff
4584  $temp = preg_replace('#-+[^-]+-+#', '', $temp);
4585  // remove new lines
4586  $temp = str_replace(array("\r", "\n", ' '), '', $temp);
4587  $temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false;
4588  return $temp != false ? $temp : $str;
4589  }
4590 
4609  function getOID($name)
4610  {
4611  static $reverseMap;
4612  if (!isset($reverseMap)) {
4613  $reverseMap = array_flip($this->oids);
4614  }
4615  return isset($reverseMap[$name]) ? $reverseMap[$name] : $name;
4616  }
4617 }
const TYPE_VISIBLE_STRING
Definition: ASN1.php:86
const ATTR_ALL
#-
Definition: X509.php:118
const VALIDATE_SIGNATURE_BY_CA
Flag to only accept signatures signed by certificate authorities.
Definition: X509.php:52
_getExtensions($cert=null, $path=null)
Returns a list of all extensions in use.
Definition: X509.php:3893
const TYPE_UTC_TIME
Definition: ASN1.php:83
_decodeIP($ip)
Decodes an IP address.
Definition: X509.php:2200
$path
Definition: aliased.php:25
const DN_HASH
Return name hash for file indexing.
Definition: X509.php:81
_extractBER($str)
Extract raw BER from Base64 encoding.
Definition: X509.php:4571
setAttribute($id, $value, $disposition=self::ATTR_ALL)
Set a CSR attribute.
Definition: X509.php:4123
loadSPKAC($spkac)
Load a SPKAC CSR.
Definition: X509.php:2964
$size
Definition: RandomTest.php:84
setDNProp($propName, $propValue, $type='utf8String')
Set a Distinguished Name property.
Definition: X509.php:2319
_reformatKey($algorithm, $key)
Reformat public keys.
Definition: X509.php:2175
const CLASS_CONTEXT_SPECIFIC
Definition: ASN1.php:46
Pure-PHP X.509 Parser.
$format
Definition: metadata.php:141
loadCA($cert)
Load an X.509 certificate as a certificate authority.
Definition: X509.php:1855
setPrivateKey($key)
Set private key.
Definition: X509.php:2767
validateSignature($caonly=true)
Validate a signature.
Definition: X509.php:2019
const TYPE_NUMERIC_STRING
#-
Definition: ASN1.php:78
$result
setIPAddress()
Set the IP Addresses&#39;s which the cert is to be valid for.
Definition: X509.php:4313
_sign($key, $signatureAlgorithm)
X.509 certificate signing helper function.
Definition: X509.php:3658
$type
_revokedCertificate(&$rclist, $serial, $create=false)
Get the index of a revoked certificate.
Definition: X509.php:4359
const TYPE_PRINTABLE_STRING
Definition: ASN1.php:79
const FORMAT_PEM
#-
Definition: X509.php:95
const TYPE_NULL
Definition: ASN1.php:60
getPublicKey()
Gets the public key.
Definition: X509.php:2793
setDomain()
Set the domain name&#39;s which the cert is to be valid for.
Definition: X509.php:4300
const ATTR_APPEND
Definition: X509.php:119
const FORMAT_DER
Save as DER.
Definition: X509.php:99
if(!array_key_exists('StateId', $_REQUEST)) $id
getRevoked($serial)
Get a revoked certificate.
Definition: X509.php:4433
_setExtension($id, $value, $critical=false, $replace=true, $path=null)
Set an Extension.
Definition: X509.php:3918
_mapOutExtensions(&$root, $path, $asn1)
Map extension values from extension-specific internal format to octet string.
Definition: X509.php:1611
_mapOutAttributes(&$root, $path, $asn1)
Map attribute values from attribute-specific internal format to ANY type.
Definition: X509.php:1718
getExtension($id, $cert=null)
Get a certificate, CSR or CRL Extension.
Definition: X509.php:3965
$s
Definition: pwgen.php:45
const TYPE_IA5_STRING
Definition: ASN1.php:82
getAttribute($id, $disposition=self::ATTR_ALL, $csr=null)
Get a CSR attribute.
Definition: X509.php:4056
const TYPE_CHOICE
#-
Definition: ASN1.php:100
_formatSubjectPublicKey()
Format a public key as appropriate.
Definition: X509.php:4279
getRevokedCertificateExtensions($serial, $crl=null)
Returns a list of all extensions in use for a given revoked certificate.
Definition: X509.php:4525
const TYPE_INTEGER
Definition: ASN1.php:57
_removeExtension($id, $path=null)
Remove an Extension.
Definition: X509.php:3837
_dnsName($domain)
Helper function to build domain array.
Definition: X509.php:4331
validateURL($url)
Validate an X.509 certificate against a URL.
Definition: X509.php:1922
const TYPE_SEQUENCE
Definition: ASN1.php:69
getDNProp($propName, $dn=null, $withType=false)
Get Distinguished Name properties.
Definition: X509.php:2380
const CLASS_APPLICATION
Definition: ASN1.php:45
setDN($dn, $merge=false, $type='utf8String')
Set a Distinguished Name.
Definition: X509.php:2431
getSubjectDNProp($propName, $withType=false)
Get an individual Distinguished Name property for a certificate/csr subject.
Definition: X509.php:2683
_mapInExtensions(&$root, $path, $asn1)
Map extension values from octet string to extension-specific internal format.
Definition: X509.php:1561
loadX509($cert, $mode=self::FORMAT_AUTO_DETECT)
Load X.509 certificate.
Definition: X509.php:1416
$start
Definition: bench.php:8
$base
Definition: index.php:4
$version
Definition: build.php:27
const FORMAT_AUTO_DETECT
Auto-detect the format.
Definition: X509.php:111
const TYPE_OCTET_STRING
Definition: ASN1.php:59
getAttributes($csr=null)
Returns a list of all CSR attributes in use.
Definition: X509.php:4096
const TYPE_UTF8_STRING
Definition: ASN1.php:67
getOID($name)
Returns the OID corresponding to a name.
Definition: X509.php:4609
const TYPE_UNIVERSAL_STRING
Definition: ASN1.php:88
makeCA()
Turns the certificate into a certificate authority.
Definition: X509.php:3733
getIssuerDN($format=self::DN_ARRAY)
Get the Distinguished Name for a certificate/crl issuer.
Definition: X509.php:2615
computeKeyIdentifier($key=null, $method=1)
Compute a public key identifier.
Definition: X509.php:4205
unrevoke($serial)
Unrevoke a certificate.
Definition: X509.php:4413
setSerialNumber($serial, $base=-256)
Set Serial Number.
Definition: X509.php:3723
const FORMAT_SPKAC
Save as a SPKAC.
Definition: X509.php:105
setKeyIdentifier($value)
Sets the subject key identifier.
Definition: X509.php:4178
saveSPKAC($spkac, $format=self::FORMAT_PEM)
Save a SPKAC CSR request.
Definition: X509.php:3036
Pure-PHP PKCS#1 compliant implementation of RSA.
$values
const TYPE_OBJECT_IDENTIFIER
Definition: ASN1.php:61
const TYPE_GENERALIZED_TIME
Definition: ASN1.php:84
setEndDate($date)
Set certificate end date.
Definition: X509.php:3697
sign($issuer, $subject, $signatureAlgorithm='sha1WithRSAEncryption')
Sign an X.509 certificate.
Definition: X509.php:3224
const DN_STRING
Return string.
Definition: X509.php:65
validateDate($date=null)
Validate a date.
Definition: X509.php:1979
const TYPE_ENUMERATED
Definition: ASN1.php:65
removeExtension($id)
Remove a certificate, CSR or CRL Extension.
Definition: X509.php:3950
removeRevokedCertificateExtension($serial, $id)
Remove a Revoked Certificate Extension.
Definition: X509.php:4480
Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic...
getRevokedCertificateExtension($serial, $id, $crl=null)
Get a Revoked Certificate Extension.
Definition: X509.php:4502
$n
Definition: RandomTest.php:85
$root
Definition: sabredav.php:45
if(array_key_exists('yes', $_REQUEST)) $attributes
Definition: getconsent.php:85
getSubjectDN($format=self::DN_ARRAY)
Get the Distinguished Name for a certificate/csr subject Alias of getDN()
Definition: X509.php:2637
catch(Exception $e) if(!($request instanceof \SAML2\ArtifactResolve)) $issuer
const ATTR_REPLACE
Definition: X509.php:120
__construct()
Default Constructor.
Definition: X509.php:304
getChain()
Get the certificate chain for the current cert.
Definition: X509.php:2705
& _extensions(&$root, $path=null, $create=false)
Get a reference to an extension subarray.
Definition: X509.php:3783
_getExtension($id, $cert=null, $path=null)
Get an Extension.
Definition: X509.php:3868
removeDNProp($propName)
Remove Distinguished Name properties.
Definition: X509.php:2350
setStartDate($date)
Set certificate start date.
Definition: X509.php:3686
const SIGNATURE_PKCS1
Use the PKCS#1 scheme by default.
Definition: RSA.php:124
_validateSignature($publicKeyAlgorithm, $publicKey, $signatureAlgorithm, $signature, $signatureSubject)
Validates a signature.
Definition: X509.php:2133
getIssuerDNProp($propName, $withType=false)
Get an individual Distinguished Name property for a certificate/crl issuer.
Definition: X509.php:2661
$DirectoryString
#+ ASN.1 syntax for various extensions
Definition: X509.php:135
const TYPE_TELETEX_STRING
Definition: ASN1.php:80
const TYPE_SET
Definition: ASN1.php:70
signCSR($signatureAlgorithm='sha1WithRSAEncryption')
Sign a CSR.
Definition: X509.php:3401
signSPKAC($signatureAlgorithm='sha1WithRSAEncryption')
Sign a SPKAC.
Definition: X509.php:3459
setChallenge($challenge)
Set challenge.
Definition: X509.php:2780
listRevoked($crl=null)
List revoked certificates.
Definition: X509.php:4451
saveCRL($crl, $format=self::FORMAT_PEM)
Save Certificate Revocation List.
Definition: X509.php:3140
Pure-PHP arbitrary precision integer arithmetic library.
_timeField($date)
Helper function to build a time field according to RFC 3280 section.
Definition: X509.php:3201
saveX509($cert, $format=self::FORMAT_PEM)
Save X.509 certificate.
Definition: X509.php:1485
$results
Definition: svg-scanner.php:47
getDN($format=self::DN_ARRAY, $dn=null)
Get the Distinguished Name for a certificates subject.
Definition: X509.php:2473
_mapInAttributes(&$root, $path, $asn1)
Map attribute values from ANY type to attribute-specific internal format.
Definition: X509.php:1677
setExtension($id, $value, $critical=false, $replace=true)
Set a certificate, CSR or CRL Extension.
Definition: X509.php:3992
$i
Definition: disco.tpl.php:19
_iPAddress($address)
Helper function to build IP Address array.
Definition: X509.php:4345
static string($length)
Generate a random string.
Definition: Random.php:54
$url
const PUBLIC_FORMAT_PKCS1
PKCS#1 formatted public key (raw)
Definition: RSA.php:224
const TYPE_BOOLEAN
#-
Definition: ASN1.php:56
removeAttribute($id, $disposition=self::ATTR_ALL)
Remove a CSR attribute.
Definition: X509.php:4005
getExtensions($cert=null)
Returns a list of all extensions in use in certificate, CSR or CRL.
Definition: X509.php:3977
$SignedPublicKeyAndChallenge
Definition: X509.php:168
if(!array_key_exists('domain', $_REQUEST)) $domain
Definition: resume.php:8
signCRL($issuer, $crl, $signatureAlgorithm='sha1WithRSAEncryption')
Sign a CRL.
Definition: X509.php:3529
_translateDNProp($propName)
"Normalizes" a Distinguished Name property
Definition: X509.php:2228
const TYPE_BIT_STRING
Definition: ASN1.php:58
const DN_OPENSSL
Return OpenSSL compatible array.
Definition: X509.php:73
loadCRL($crl, $mode=self::FORMAT_AUTO_DETECT)
Load a Certificate Revocation List.
Definition: X509.php:3078
_encodeIP($ip)
Encodes an IP address.
Definition: X509.php:2216
revoke($serial, $date=null)
Revoke a certificate.
Definition: X509.php:4387
const DN_CANON
Return canonical ASN.1 RDNs string.
Definition: X509.php:77
$key
Definition: croninfo.php:18
saveCSR($csr, $format=self::FORMAT_PEM)
Save CSR request.
Definition: X509.php:2913
_getMapping($extnId)
Associate an extension ID to an extension mapping.
Definition: X509.php:1759
setPublicKey($key)
Set public key.
Definition: X509.php:2753
const TYPE_BMP_STRING
Definition: ASN1.php:90
const DN_ARRAY
#+ public
Definition: X509.php:61
& _subArray(&$root, $path, $create=false)
Get a reference to a subarray.
Definition: X509.php:3747
loadCSR($csr, $mode=self::FORMAT_AUTO_DETECT)
Load a Certificate Signing Request.
Definition: X509.php:2833
setRevokedCertificateExtension($serial, $id, $value, $critical=false, $replace=true)
Set a Revoked Certificate Extension.
Definition: X509.php:4551
ASN.1 Element.
const DN_ASN1
Return ASN.1 name string.
Definition: X509.php:69