ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
X509.php
Go to the documentation of this file.
1<?php
2
27namespace phpseclib\File;
28
35
43class 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
155
159
160 var $Name;
178
186
193 var $dn;
194
202
210
218 var $oids;
219
226 var $CAs;
227
235
246
254
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(
537 'constant' => 0,
538 'optional' => true,
539 'implicit' => true
540 ),
541 'given-name' => array(
543 'constant' => 1,
544 'optional' => true,
545 'implicit' => true
546 ),
547 'initials' => array(
549 'constant' => 2,
550 'optional' => true,
551 'implicit' => true
552 ),
553 'generation-qualifier' => array(
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(
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,
950 'notAfter' => array(
951 'constant' => 1,
952 'optional' => true,
953 'implicit' => true,
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':
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':
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':
1792
1793 case 'netscape-cert-type':
1795 case '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':
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':
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
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
2754 {
2755 $key->setPublicKey();
2756 $this->publicKey = $key;
2757 }
2758
2768 {
2769 $this->privateKey = $key;
2770 }
2771
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();
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
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}
catch(Exception $e) if(!($request instanceof \SAML2\ArtifactResolve)) $issuer
$result
$n
Definition: RandomTest.php:85
$size
Definition: RandomTest.php:84
$path
Definition: aliased.php:25
$version
Definition: build.php:27
if(!array_key_exists('domain', $_REQUEST)) $domain
Definition: resume.php:8
An exception for terminatinating execution or to throw for unit testing.
const PUBLIC_FORMAT_PKCS1
PKCS#1 formatted public key (raw)
Definition: RSA.php:224
const SIGNATURE_PKCS1
Use the PKCS#1 scheme by default.
Definition: RSA.php:124
static string($length)
Generate a random string.
Definition: Random.php:54
const TYPE_PRINTABLE_STRING
Definition: ASN1.php:79
const CLASS_APPLICATION
Definition: ASN1.php:45
const TYPE_OBJECT_IDENTIFIER
Definition: ASN1.php:61
const TYPE_IA5_STRING
Definition: ASN1.php:82
const TYPE_OCTET_STRING
Definition: ASN1.php:59
const TYPE_TELETEX_STRING
Definition: ASN1.php:80
const TYPE_BMP_STRING
Definition: ASN1.php:90
const TYPE_SEQUENCE
Definition: ASN1.php:69
const TYPE_SET
Definition: ASN1.php:70
const TYPE_BIT_STRING
Definition: ASN1.php:58
const TYPE_GENERALIZED_TIME
Definition: ASN1.php:84
const TYPE_UNIVERSAL_STRING
Definition: ASN1.php:88
const TYPE_VISIBLE_STRING
Definition: ASN1.php:86
const TYPE_UTF8_STRING
Definition: ASN1.php:67
const CLASS_CONTEXT_SPECIFIC
Definition: ASN1.php:46
const TYPE_CHOICE
#-
Definition: ASN1.php:100
const TYPE_UTC_TIME
Definition: ASN1.php:83
const TYPE_NUMERIC_STRING
#-
Definition: ASN1.php:78
const TYPE_NULL
Definition: ASN1.php:60
const TYPE_ENUMERATED
Definition: ASN1.php:65
const TYPE_BOOLEAN
#-
Definition: ASN1.php:56
const TYPE_INTEGER
Definition: ASN1.php:57
setStartDate($date)
Set certificate start date.
Definition: X509.php:3686
& _extensions(&$root, $path=null, $create=false)
Get a reference to an extension subarray.
Definition: X509.php:3783
_getMapping($extnId)
Associate an extension ID to an extension mapping.
Definition: X509.php:1759
const FORMAT_AUTO_DETECT
Auto-detect the format.
Definition: X509.php:111
setKeyIdentifier($value)
Sets the subject key identifier.
Definition: X509.php:4178
getChain()
Get the certificate chain for the current cert.
Definition: X509.php:2705
setRevokedCertificateExtension($serial, $id, $value, $critical=false, $replace=true)
Set a Revoked Certificate Extension.
Definition: X509.php:4551
$DirectoryString
#+ ASN.1 syntax for various extensions
Definition: X509.php:135
validateDate($date=null)
Validate a date.
Definition: X509.php:1979
getOID($name)
Returns the OID corresponding to a name.
Definition: X509.php:4609
setDNProp($propName, $propValue, $type='utf8String')
Set a Distinguished Name property.
Definition: X509.php:2319
getDNProp($propName, $dn=null, $withType=false)
Get Distinguished Name properties.
Definition: X509.php:2380
_mapInExtensions(&$root, $path, $asn1)
Map extension values from octet string to extension-specific internal format.
Definition: X509.php:1561
_sign($key, $signatureAlgorithm)
X.509 certificate signing helper function.
Definition: X509.php:3658
getAttribute($id, $disposition=self::ATTR_ALL, $csr=null)
Get a CSR attribute.
Definition: X509.php:4056
setPrivateKey($key)
Set private key.
Definition: X509.php:2767
_formatSubjectPublicKey()
Format a public key as appropriate.
Definition: X509.php:4279
_setExtension($id, $value, $critical=false, $replace=true, $path=null)
Set an Extension.
Definition: X509.php:3918
const DN_CANON
Return canonical ASN.1 RDNs string.
Definition: X509.php:77
getExtensions($cert=null)
Returns a list of all extensions in use in certificate, CSR or CRL.
Definition: X509.php:3977
_validateSignature($publicKeyAlgorithm, $publicKey, $signatureAlgorithm, $signature, $signatureSubject)
Validates a signature.
Definition: X509.php:2133
getPublicKey()
Gets the public key.
Definition: X509.php:2793
& _subArray(&$root, $path, $create=false)
Get a reference to a subarray.
Definition: X509.php:3747
saveX509($cert, $format=self::FORMAT_PEM)
Save X.509 certificate.
Definition: X509.php:1485
setPublicKey($key)
Set public key.
Definition: X509.php:2753
_revokedCertificate(&$rclist, $serial, $create=false)
Get the index of a revoked certificate.
Definition: X509.php:4359
signSPKAC($signatureAlgorithm='sha1WithRSAEncryption')
Sign a SPKAC.
Definition: X509.php:3459
__construct()
Default Constructor.
Definition: X509.php:304
const DN_OPENSSL
Return OpenSSL compatible array.
Definition: X509.php:73
setSerialNumber($serial, $base=-256)
Set Serial Number.
Definition: X509.php:3723
loadCA($cert)
Load an X.509 certificate as a certificate authority.
Definition: X509.php:1855
makeCA()
Turns the certificate into a certificate authority.
Definition: X509.php:3733
listRevoked($crl=null)
List revoked certificates.
Definition: X509.php:4451
setIPAddress()
Set the IP Addresses's which the cert is to be valid for.
Definition: X509.php:4313
computeKeyIdentifier($key=null, $method=1)
Compute a public key identifier.
Definition: X509.php:4205
setAttribute($id, $value, $disposition=self::ATTR_ALL)
Set a CSR attribute.
Definition: X509.php:4123
saveCRL($crl, $format=self::FORMAT_PEM)
Save Certificate Revocation List.
Definition: X509.php:3140
sign($issuer, $subject, $signatureAlgorithm='sha1WithRSAEncryption')
Sign an X.509 certificate.
Definition: X509.php:3224
loadCRL($crl, $mode=self::FORMAT_AUTO_DETECT)
Load a Certificate Revocation List.
Definition: X509.php:3078
getRevokedCertificateExtensions($serial, $crl=null)
Returns a list of all extensions in use for a given revoked certificate.
Definition: X509.php:4525
const DN_STRING
Return string.
Definition: X509.php:65
_dnsName($domain)
Helper function to build domain array.
Definition: X509.php:4331
getExtension($id, $cert=null)
Get a certificate, CSR or CRL Extension.
Definition: X509.php:3965
getAttributes($csr=null)
Returns a list of all CSR attributes in use.
Definition: X509.php:4096
unrevoke($serial)
Unrevoke a certificate.
Definition: X509.php:4413
saveSPKAC($spkac, $format=self::FORMAT_PEM)
Save a SPKAC CSR request.
Definition: X509.php:3036
const DN_ASN1
Return ASN.1 name string.
Definition: X509.php:69
setDomain()
Set the domain name's which the cert is to be valid for.
Definition: X509.php:4300
revoke($serial, $date=null)
Revoke a certificate.
Definition: X509.php:4387
_encodeIP($ip)
Encodes an IP address.
Definition: X509.php:2216
_getExtensions($cert=null, $path=null)
Returns a list of all extensions in use.
Definition: X509.php:3893
_iPAddress($address)
Helper function to build IP Address array.
Definition: X509.php:4345
removeDNProp($propName)
Remove Distinguished Name properties.
Definition: X509.php:2350
signCSR($signatureAlgorithm='sha1WithRSAEncryption')
Sign a CSR.
Definition: X509.php:3401
const VALIDATE_SIGNATURE_BY_CA
Flag to only accept signatures signed by certificate authorities.
Definition: X509.php:52
getSubjectDN($format=self::DN_ARRAY)
Get the Distinguished Name for a certificate/csr subject Alias of getDN()
Definition: X509.php:2637
removeExtension($id)
Remove a certificate, CSR or CRL Extension.
Definition: X509.php:3950
getSubjectDNProp($propName, $withType=false)
Get an individual Distinguished Name property for a certificate/csr subject.
Definition: X509.php:2683
getIssuerDNProp($propName, $withType=false)
Get an individual Distinguished Name property for a certificate/crl issuer.
Definition: X509.php:2661
setEndDate($date)
Set certificate end date.
Definition: X509.php:3697
const ATTR_REPLACE
Definition: X509.php:120
const ATTR_APPEND
Definition: X509.php:119
_removeExtension($id, $path=null)
Remove an Extension.
Definition: X509.php:3837
setChallenge($challenge)
Set challenge.
Definition: X509.php:2780
loadSPKAC($spkac)
Load a SPKAC CSR.
Definition: X509.php:2964
const FORMAT_DER
Save as DER.
Definition: X509.php:99
_reformatKey($algorithm, $key)
Reformat public keys.
Definition: X509.php:2175
validateURL($url)
Validate an X.509 certificate against a URL.
Definition: X509.php:1922
const DN_ARRAY
#+ @access public
Definition: X509.php:61
loadX509($cert, $mode=self::FORMAT_AUTO_DETECT)
Load X.509 certificate.
Definition: X509.php:1416
getIssuerDN($format=self::DN_ARRAY)
Get the Distinguished Name for a certificate/crl issuer.
Definition: X509.php:2615
setDN($dn, $merge=false, $type='utf8String')
Set a Distinguished Name.
Definition: X509.php:2431
_getExtension($id, $cert=null, $path=null)
Get an Extension.
Definition: X509.php:3868
_mapOutExtensions(&$root, $path, $asn1)
Map extension values from extension-specific internal format to octet string.
Definition: X509.php:1611
const FORMAT_SPKAC
Save as a SPKAC.
Definition: X509.php:105
validateSignature($caonly=true)
Validate a signature.
Definition: X509.php:2019
getRevoked($serial)
Get a revoked certificate.
Definition: X509.php:4433
removeRevokedCertificateExtension($serial, $id)
Remove a Revoked Certificate Extension.
Definition: X509.php:4480
_timeField($date)
Helper function to build a time field according to RFC 3280 section.
Definition: X509.php:3201
_decodeIP($ip)
Decodes an IP address.
Definition: X509.php:2200
const FORMAT_PEM
#-
Definition: X509.php:95
getRevokedCertificateExtension($serial, $id, $crl=null)
Get a Revoked Certificate Extension.
Definition: X509.php:4502
getDN($format=self::DN_ARRAY, $dn=null)
Get the Distinguished Name for a certificates subject.
Definition: X509.php:2473
_mapOutAttributes(&$root, $path, $asn1)
Map attribute values from attribute-specific internal format to ANY type.
Definition: X509.php:1718
$SignedPublicKeyAndChallenge
Definition: X509.php:168
_extractBER($str)
Extract raw BER from Base64 encoding.
Definition: X509.php:4571
loadCSR($csr, $mode=self::FORMAT_AUTO_DETECT)
Load a Certificate Signing Request.
Definition: X509.php:2833
const DN_HASH
Return name hash for file indexing.
Definition: X509.php:81
_translateDNProp($propName)
"Normalizes" a Distinguished Name property
Definition: X509.php:2228
saveCSR($csr, $format=self::FORMAT_PEM)
Save CSR request.
Definition: X509.php:2913
setExtension($id, $value, $critical=false, $replace=true)
Set a certificate, CSR or CRL Extension.
Definition: X509.php:3992
_mapInAttributes(&$root, $path, $asn1)
Map attribute values from ANY type to attribute-specific internal format.
Definition: X509.php:1677
const ATTR_ALL
#-
Definition: X509.php:118
removeAttribute($id, $disposition=self::ATTR_ALL)
Remove a CSR attribute.
Definition: X509.php:4005
signCRL($issuer, $crl, $signatureAlgorithm='sha1WithRSAEncryption')
Sign a CRL.
Definition: X509.php:3529
$key
Definition: croninfo.php:18
$i
Definition: disco.tpl.php:19
if(!array_key_exists('StateId', $_REQUEST)) $id
if(array_key_exists('yes', $_REQUEST)) $attributes
Definition: getconsent.php:85
$base
Definition: index.php:4
$format
Definition: metadata.php:141
Pure-PHP ASN.1 Parser.
Pure-PHP arbitrary precision integer arithmetic library.
Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic...
Pure-PHP PKCS#1 compliant implementation of RSA.
Pure-PHP X.509 Parser.
$type
$url
$s
Definition: pwgen.php:45
$root
Definition: sabredav.php:45
echo;exit;}function LogoutNotification($SessionID){ global $ilDB;$q="SELECT session_id, data FROM usr_session WHERE expires > (\w+)\|/" PREG_SPLIT_NO_EMPTY PREG_SPLIT_DELIM_CAPTURE
$results
Definition: svg-scanner.php:47
$values
$start
Definition: bench.php:8