commit
7b222d9edb
|
@ -3,7 +3,7 @@ addons:
|
|||
sonarcloud:
|
||||
organization: "ldap-account-manager"
|
||||
php:
|
||||
- '5.6'
|
||||
- '7.3'
|
||||
|
||||
cache:
|
||||
directories:
|
||||
|
|
|
@ -179,6 +179,7 @@ A:
|
|||
information, contact: tavmjong @ free . fr.
|
||||
|
||||
B:
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
|
@ -200,6 +201,7 @@ B:
|
|||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
C:
|
||||
New BSD License
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
@ -391,6 +393,7 @@ D:
|
|||
Library.
|
||||
|
||||
E:
|
||||
Duo
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
|
@ -415,10 +418,73 @@ E:
|
|||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
F:
|
||||
3-Clause BSD License
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
G:
|
||||
2-Clause BSD License
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
Programs and licenses with other licenses and/or authors than the
|
||||
main license and authors:
|
||||
|
||||
lib/3rdParty/composer/beberlei G 2013 Benjamin Eberlei
|
||||
lib/3rdParty/composer/composer B Nils Adermann, Jordi Boggiano
|
||||
lib/3rdParty/composer/fgrosse B 2015 Friedrich Große
|
||||
lib/3rdParty/composer/nyholm B 2016 Tobias Nyholm
|
||||
lib/3rdParty/composer/paragonie B 2015 Paragon Initiative Enterprises
|
||||
lib/3rdParty/composer/php-http B 2015 PHP HTTP Team
|
||||
lib/3rdParty/composer/psr B 2018 PHP Framework Interoperability Group
|
||||
lib/3rdParty/composer/ramsey B 2018 Ben Ramsey
|
||||
lib/3rdParty/composer/spomky-labs B 2018 Spomky-Labs
|
||||
lib/3rdParty/composer/symfony B 2019 Fabien Potencier
|
||||
lib/3rdParty/composer/web-auth B 2018 Spomky-Labs
|
||||
lib/3rdParty/tcpdf D 2018 Nicola Asuni - Tecnick.com LTD
|
||||
lib/3rdParty/tcpdf/fonts/DejaVu*.ttf A Public Domain, Bitstream, Inc., Tavmjong Bah
|
||||
lib/3rdParty/tcpdf/fonts/DejaVu*.z A Public Domain, Bitstream, Inc., Tavmjong Bah
|
||||
|
@ -438,6 +504,7 @@ templates/lib/extra/cropperjs B 2018 Chen Fengyuan
|
|||
style/600_cropper*.css B 2018 Chen Fengyuan
|
||||
templates/lib/extra/duo/*.js E 2019 Duo Security
|
||||
lib/3rdParty/duo/*.php E 2019 Duo Security
|
||||
graphics/webauthn.svg F 2017 Duo Security, Inc.
|
||||
templates/lib/600_jquery.magnific-popup.js B 2016 Dmitry Semenov
|
||||
style/610_magnific-popup.css B 2016 Dmitry Semenov
|
||||
style/responsive/105_normalize.css B Nicolas Gallagher and Jonathan Neal
|
||||
|
|
|
@ -51,6 +51,7 @@ RUN apt-get update && \
|
|||
php-phpseclib \
|
||||
php-xml \
|
||||
php-zip \
|
||||
php-imap \
|
||||
wget \
|
||||
&& \
|
||||
rm /etc/apache2/sites-enabled/*default* && \
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
March 2020 7.1
|
||||
- PHP 7 required
|
||||
- Webauthn/FIDO2 support for 2-factor-authentication (requires PHP 7.2)
|
||||
|
||||
|
||||
21.12.2019 7.0
|
||||
- Lamdaemon can be configured with directory prefix for homedirs
|
||||
- Account list filters match on substrings instead of whole value
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"config": {
|
||||
"vendor-dir": "lib/3rdParty/composer"
|
||||
},
|
||||
"require" : {
|
||||
"web-auth/webauthn-lib" : "2.1.7",
|
||||
"symfony/http-foundation" : "5.0.0",
|
||||
"symfony/psr-http-message-bridge" : "1.3.0"
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -3,3 +3,4 @@ config.cfg
|
|||
/serverCerts.pem
|
||||
/pdf/
|
||||
/profiles/
|
||||
*.sqlite
|
|
@ -178,6 +178,7 @@ A:
|
|||
information, contact: tavmjong @ free . fr.
|
||||
|
||||
B:
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
|
@ -199,6 +200,7 @@ B:
|
|||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
C:
|
||||
New BSD License
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
@ -390,6 +392,7 @@ D:
|
|||
Library.
|
||||
|
||||
E:
|
||||
Duo
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
|
@ -414,10 +417,73 @@ E:
|
|||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
F:
|
||||
3-Clause BSD License
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
G:
|
||||
2-Clause BSD License
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
Programs and licenses with other licenses and/or authors than the
|
||||
main license and authors:
|
||||
|
||||
lib/3rdParty/composer/beberlei G 2013 Benjamin Eberlei
|
||||
lib/3rdParty/composer/composer B Nils Adermann, Jordi Boggiano
|
||||
lib/3rdParty/composer/fgrosse B 2015 Friedrich Große
|
||||
lib/3rdParty/composer/nyholm B 2016 Tobias Nyholm
|
||||
lib/3rdParty/composer/paragonie B 2015 Paragon Initiative Enterprises
|
||||
lib/3rdParty/composer/php-http B 2015 PHP HTTP Team
|
||||
lib/3rdParty/composer/psr B 2018 PHP Framework Interoperability Group
|
||||
lib/3rdParty/composer/ramsey B 2018 Ben Ramsey
|
||||
lib/3rdParty/composer/spomky-labs B 2018 Spomky-Labs
|
||||
lib/3rdParty/composer/symfony B 2019 Fabien Potencier
|
||||
lib/3rdParty/composer/web-auth B 2018 Spomky-Labs
|
||||
lib/3rdParty/tcpdf D 2018 Nicola Asuni - Tecnick.com LTD
|
||||
lib/3rdParty/tcpdf/fonts/DejaVu*.ttf A Public Domain, Bitstream, Inc., Tavmjong Bah
|
||||
lib/3rdParty/tcpdf/fonts/DejaVu*.z A Public Domain, Bitstream, Inc., Tavmjong Bah
|
||||
|
@ -437,6 +503,7 @@ templates/lib/extra/cropperjs B 2018 Chen Fengyuan
|
|||
style/600_cropper*.css B 2018 Chen Fengyuan
|
||||
templates/lib/extra/duo/*.js E 2019 Duo Security
|
||||
lib/3rdParty/duo/*.php E 2019 Duo Security
|
||||
graphics/webauthn.svg F 2017 Duo Security, Inc.
|
||||
templates/lib/600_jquery.magnific-popup.js B 2016 Dmitry Semenov
|
||||
style/610_magnific-popup.css B 2016 Dmitry Semenov
|
||||
style/responsive/105_normalize.css B Nicolas Gallagher and Jonathan Neal
|
||||
|
|
|
@ -445,4 +445,51 @@ semodule -i httpdlocal.pp</programlisting>
|
|||
</programlisting>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="a_webauthn">
|
||||
<title>Webauthn/FIDO2</title>
|
||||
|
||||
<para>LAM allows to secure logins via <ulink
|
||||
url="https://en.wikipedia.org/wiki/WebAuthn">Webauthn/FIDO2</ulink>. This
|
||||
means your users login with their LDAP password and an additional hardware
|
||||
token (e.g. Yubico Security Key, Windows Hello and many more).</para>
|
||||
|
||||
<para>Webauthn/FIDO2 is a very strong 2-factor-authentication method as it
|
||||
also checks the website domain. This prevents attacks via web
|
||||
proxies.</para>
|
||||
|
||||
<para>To use this feature you need to activate the 2-factor authentication
|
||||
in LAM.</para>
|
||||
|
||||
<para><emphasis role="bold">LAM admin interface</emphasis></para>
|
||||
|
||||
<para>Please activate Webauthn/FIDO2 in your <link
|
||||
linkend="conf_serverprofile_2fa">LAM server profile</link>. Then users
|
||||
will be asked to authenticate via Webauthn/FIDO2 on each login.</para>
|
||||
|
||||
<para>If no device is registered for a user then LAM will ask for this
|
||||
during login. Afterwards, users can manage their devices with the <link
|
||||
linkend="tool_webauthn">Webauthn tool</link>.</para>
|
||||
|
||||
<para><emphasis role="bold">LAM Self Service</emphasis></para>
|
||||
|
||||
<para>Please activate Webauthn/FIDO2 in your <link
|
||||
linkend="selfservice_2fa">LAM self service profile</link>. Then users will
|
||||
be asked to authenticate via Webauthn/FIDO2 on each login.</para>
|
||||
|
||||
<para>If no device is registered for a user then LAM will ask for this
|
||||
during login. Afterwards, users can manage their devices with the <link
|
||||
linkend="selfservice_fields">Webauthn field</link>.</para>
|
||||
|
||||
<para><emphasis role="bold">Global device management</emphasis></para>
|
||||
|
||||
<para>This is for cases where one of your users has no more access to his
|
||||
device and cannot login anymore. In this case you can delete his device(s)
|
||||
in the <link linkend="confmain_webauthn">LAM main
|
||||
configuration</link>.</para>
|
||||
|
||||
<para>Note that devices can only be deleted. Registration of devices can
|
||||
only be done by the user during login or on the management pages listed
|
||||
above.</para>
|
||||
</section>
|
||||
</appendix>
|
||||
|
|
|
@ -259,6 +259,33 @@
|
|||
</screenshot>
|
||||
</section>
|
||||
|
||||
<section id="confmain_webauthn">
|
||||
<title>Webauthn/FIDO2 devices</title>
|
||||
|
||||
<para>See the <link linkend="a_webauthn">Webauthn/FIDO2 appendix</link>
|
||||
for an overview about Webauthn/FIDO2 in LAM.</para>
|
||||
|
||||
<para>Here you can delete any webauthn device registrations. This
|
||||
section is only shown if at least one device is registered.</para>
|
||||
|
||||
<para>Enter a part of the user's DN in the input box and perform a
|
||||
search. LAM will show users and devices that match the search. You can
|
||||
then delete a device registration. If the user has no more registered
|
||||
devices then LAM will ask for registration on next login.</para>
|
||||
|
||||
<para>Note: You cannot add any device here. This can only be done by the
|
||||
user during login, <link linkend="tool_webauthn">webauthn tool</link> or
|
||||
self service.</para>
|
||||
|
||||
<para><screenshot>
|
||||
<mediaobject>
|
||||
<imageobject>
|
||||
<imagedata fileref="images/configGeneral8.png"/>
|
||||
</imageobject>
|
||||
</mediaobject>
|
||||
</screenshot></para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Change master password</title>
|
||||
|
||||
|
@ -631,7 +658,8 @@
|
|||
</mediaobject>
|
||||
</screenshot>
|
||||
|
||||
<para><emphasis role="bold">2-factor authentication</emphasis></para>
|
||||
<para id="conf_serverprofile_2fa"><emphasis role="bold">2-factor
|
||||
authentication</emphasis></para>
|
||||
|
||||
<para>LAM supports 2-factor authentication for your users. This means
|
||||
the user will not only authenticate by user+password but also with
|
||||
|
@ -655,6 +683,11 @@
|
|||
<listitem>
|
||||
<para><ulink url="https://duo.com/">Duo</ulink></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><ulink
|
||||
url="https://webauthn.io/">Webauthn/FIDO2</ulink></para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>Configuration options:</para>
|
||||
|
@ -752,6 +785,30 @@
|
|||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para><emphasis role="bold">Webauthn/FIDO2</emphasis></para>
|
||||
|
||||
<para>See the <link linkend="a_webauthn">Webauthn/FIDO2
|
||||
appendix</link> for an overview about Webauthn/FIDO2 in LAM.</para>
|
||||
|
||||
<para>Users will be asked to register a device during login if no
|
||||
device is setup.</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>Domain: Please enter the WebAuthn domain. This is the public
|
||||
domain of the web server (e.g. "example.com"). Do not include
|
||||
protocol or port. Browsers will reject authentication if the
|
||||
domain does not match the web server domain.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Optional: By default LAM will enforce to use a 2FA device
|
||||
and reject users that do not setup one. You can set this check to
|
||||
optional. But if a user has setup a device then this will always
|
||||
be required.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<screenshot>
|
||||
<mediaobject>
|
||||
<imageobject>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>Apache/Nginx webserver (SSL recommended) with PHP module (PHP
|
||||
(>= 5.6.0) with ldap, gettext, xml, openssl and optional
|
||||
(>= 7.0.0) with ldap, gettext, xml, openssl and optional
|
||||
OpenSSL)</para>
|
||||
</listitem>
|
||||
|
||||
|
|
|
@ -304,7 +304,7 @@
|
|||
|
||||
<para/>
|
||||
|
||||
<section>
|
||||
<section id="selfservice_2fa">
|
||||
<title>2-factor authentication</title>
|
||||
|
||||
<para>LAM supports 2-factor authentication for your users. This means
|
||||
|
@ -329,6 +329,11 @@
|
|||
<listitem>
|
||||
<para><ulink url="https://duo.com/">Duo</ulink></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><ulink
|
||||
url="https://en.wikipedia.org/wiki/WebAuthn">Webauthn/FIDO2</ulink></para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para><emphasis role="bold">privacyIDEA</emphasis></para>
|
||||
|
@ -424,6 +429,30 @@
|
|||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para><emphasis role="bold">Webauthn/FIDO2</emphasis></para>
|
||||
|
||||
<para>See the <link linkend="a_webauthn">Webauthn/FIDO2
|
||||
appendix</link> for an overview about Webauthn/FIDO2 in LAM.</para>
|
||||
|
||||
<para>Users will be asked to register a device during login if no
|
||||
device is setup.</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>Domain: Please enter the WebAuthn domain. This is the public
|
||||
domain of the web server (e.g. "example.com"). Do not include
|
||||
protocol or port. Browsers will reject authentication if the
|
||||
domain does not match the web server domain.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Optional: By default LAM will enforce to use a 2FA device
|
||||
and reject users that do not setup one. You can set this check to
|
||||
optional. But if a user has setup a device then this will always
|
||||
be required.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<screenshot>
|
||||
<mediaobject>
|
||||
<imageobject>
|
||||
|
@ -495,7 +524,8 @@
|
|||
</mediaobject>
|
||||
</screenshot>
|
||||
|
||||
<para><emphasis role="bold">Possible input fields</emphasis></para>
|
||||
<para id="selfservice_fields"><emphasis role="bold">Possible input
|
||||
fields</emphasis></para>
|
||||
|
||||
<para>This is a list of input fields you may add to the self service
|
||||
page.</para>
|
||||
|
@ -985,6 +1015,19 @@
|
|||
each time the Windows password is changed.</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><inlinemediaobject>
|
||||
<imageobject>
|
||||
<imagedata fileref="images/webauthn.png"/>
|
||||
</imageobject>
|
||||
</inlinemediaobject>Webauthn</entry>
|
||||
|
||||
<entry>Webauthn devices</entry>
|
||||
|
||||
<entry>Allows the user to manage his webauthn/FIDO2 security
|
||||
keys.</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry morerows="1"><inlinemediaobject>
|
||||
<imageobject>
|
||||
|
|
|
@ -420,6 +420,23 @@
|
|||
</screenshot>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title id="tool_webauthn">Webauthn devices</title>
|
||||
|
||||
<para>See the <link linkend="a_webauthn">Webauthn/FIDO2 appendix</link>
|
||||
for an overview about Webauthn/FIDO2 in LAM.</para>
|
||||
|
||||
<para>Here you can manage your webauthn/FIDO2 devices.</para>
|
||||
|
||||
<para>You can register additional security devices and remove old ones. If
|
||||
no more device is registered then LAM will ask you for registration on
|
||||
next login.</para>
|
||||
|
||||
<screenshot>
|
||||
<graphic fileref="images/tool_webauthn1.png"/>
|
||||
</screenshot>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Tests</title>
|
||||
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 35 KiB |
Binary file not shown.
After Width: | Height: | Size: 62 KiB |
Binary file not shown.
After Width: | Height: | Size: 810 B |
|
@ -63,7 +63,7 @@
|
|||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>PHP (>= 5.6.0)</para>
|
||||
<para>PHP (>= 7.0.0)</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 810 B |
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 27 KiB |
|
@ -179,6 +179,8 @@ $helpArray = array (
|
|||
"Text" => _("Here you can input simple filter expressions (e.g. 'value' or 'v*'). The filter is case-insensitive.")),
|
||||
"251" => array ("Headline" => _("Remote server"),
|
||||
"Text" => _("Please enter the syslog remote server in format \"server:port\".")),
|
||||
"252" => array ("Headline" => _("User DN"),
|
||||
"Text" => _("Please enter a part of the user's DN to search for registered devices.")),
|
||||
"260" => array ("Headline" => _("Additional LDAP filter"),
|
||||
"Text" => _('Use this to enter an additional LDAP filter (e.g. "(cn!=admin)") to reduce the number of visible elements for this account type.')
|
||||
. ' ' . _('You can use the wildcard @@LOGIN_DN@@ which will be substituted with the DN of the user who is currently logged in to LAM.')
|
||||
|
@ -329,6 +331,8 @@ $helpArray = array (
|
|||
"Text" => _('This text is displayed as footer on the self service main page.')),
|
||||
"528" => array ("Headline" => _('User name attribute'),
|
||||
"Text" => _('The attribute (e.g. "uid") that contains the user name for the 2-factor service.')),
|
||||
"529" => array ("Headline" => _('Domain'),
|
||||
"Text" => _('Please enter the WebAuthn domain. This is the public domain of the webserver (e.g. "example.com"). Do not include protocol or port.')),
|
||||
"550" => array ("Headline" => _("From address"),
|
||||
"Text" => _("This email address will be set as sender address of all password mails. If empty the system default (php.ini) will be used.")),
|
||||
"551" => array ("Headline" => _("Subject"),
|
||||
|
|
|
@ -1,14 +1,23 @@
|
|||
<?php
|
||||
namespace LAM\LIB\TWO_FACTOR;
|
||||
use \htmlResponsiveRow;
|
||||
use \LAM\LOGIN\WEBAUTHN\WebauthnManager;
|
||||
use \selfServiceProfile;
|
||||
use \LAMConfig;
|
||||
use \htmlScript;
|
||||
use \htmlIframe;
|
||||
use \htmlImage;
|
||||
use \htmlButton;
|
||||
use \htmlJavaScript;
|
||||
use \htmlStatusMessage;
|
||||
use \htmlOutputText;
|
||||
use \htmlDiv;
|
||||
use \LAMException;
|
||||
use \Webauthn\PublicKeyCredentialCreationOptions;
|
||||
|
||||
/*
|
||||
This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/)
|
||||
Copyright (C) 2017 - 2019 Roland Gruber
|
||||
Copyright (C) 2017 - 2020 Roland Gruber
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -455,7 +464,7 @@ class DuoProvider extends BaseProvider {
|
|||
* @see \LAM\LIB\TWO_FACTOR\TwoFactorProvider::verify2ndFactor()
|
||||
*/
|
||||
public function verify2ndFactor($user, $password, $serial, $twoFactorInput) {
|
||||
logNewMessage(LOG_DEBUG, 'PrivacyIDEAProvider: Checking 2nd factor for ' . $user);
|
||||
logNewMessage(LOG_DEBUG, 'DuoProvider: Checking 2nd factor for ' . $user);
|
||||
$loginAttribute = $this->getLoginAttributeValue($user);
|
||||
$response = $_POST['sig_response'];
|
||||
include_once(__DIR__ . "/3rdParty/duo/Web.php");
|
||||
|
@ -473,6 +482,140 @@ class DuoProvider extends BaseProvider {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Provider for Webauthn.
|
||||
*/
|
||||
class WebauthnProvider extends BaseProvider {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param TwoFactorConfiguration $config configuration
|
||||
*/
|
||||
public function __construct($config) {
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see \LAM\LIB\TWO_FACTOR\TwoFactorProvider::getSerials()
|
||||
*/
|
||||
public function getSerials($user, $password) {
|
||||
return array('WEBAUTHN');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see \LAM\LIB\TWO_FACTOR\TwoFactorProvider::isShowSubmitButton()
|
||||
*/
|
||||
public function isShowSubmitButton() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see \LAM\LIB\TWO_FACTOR\TwoFactorProvider::hasCustomInputForm()
|
||||
*/
|
||||
public function hasCustomInputForm() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see \LAM\LIB\TWO_FACTOR\BaseProvider::addCustomInput()
|
||||
*/
|
||||
public function addCustomInput(&$row, $userDn) {
|
||||
if (version_compare(phpversion(), '7.2.0') < 0) {
|
||||
$row->add(new htmlStatusMessage('ERROR', 'Webauthn requires PHP 7.2.'), 12);
|
||||
return;
|
||||
}
|
||||
if (!extension_loaded('PDO')) {
|
||||
$row->add(new htmlStatusMessage('ERROR', 'Webauthn requires the PDO extension for PHP.'), 12);
|
||||
return;
|
||||
}
|
||||
$pdoDrivers = \PDO::getAvailableDrivers();
|
||||
if (!in_array('sqlite', $pdoDrivers)) {
|
||||
$row->add(new htmlStatusMessage('ERROR', 'Webauthn requires the sqlite PDO driver for PHP.'), 12);
|
||||
return;
|
||||
}
|
||||
include_once __DIR__ . '/webauthn.inc';
|
||||
$webauthnManager = $this->getWebauthnManager();
|
||||
$hasTokens = $webauthnManager->isRegistered($userDn);
|
||||
if ($hasTokens) {
|
||||
$row->add(new htmlStatusMessage('INFO', _('Please authenticate with your security device.')), 12);
|
||||
}
|
||||
else {
|
||||
$row->add(new htmlStatusMessage('INFO', _('Please register a security device.')), 12);
|
||||
}
|
||||
$row->addVerticalSpacer('2rem');
|
||||
$pathPrefix = $this->config->isSelfService ? '../' : '';
|
||||
$selfServiceParam = $this->config->isSelfService ? 'true' : 'false';
|
||||
$row->add(new htmlImage($pathPrefix . '../graphics/webauthn.svg'), 12);
|
||||
$row->addVerticalSpacer('1rem');
|
||||
$registerButton = new htmlButton('register_webauthn', _('Register new key'));
|
||||
$registerButton->setCSSClasses(array('fullwidth hidden'));
|
||||
$row->add($registerButton, 12);
|
||||
$loginButton = new htmlButton('login_webauthn', _('Login'));
|
||||
$loginButton->setCSSClasses(array('fullwidth hidden'));
|
||||
$row->add($loginButton, 12);
|
||||
$errorMessage = new htmlStatusMessage('ERROR', '', _('This service requires a browser with "WebAuthn" support.'));
|
||||
$row->add(new htmlDiv(null, $errorMessage, array('hidden webauthn-error')), 12);
|
||||
if ($this->config->twoFactorAuthenticationOptional === true) {
|
||||
if (!$hasTokens) {
|
||||
$skipButton = new htmlButton('skip_webauthn', _('Skip'));
|
||||
$skipButton->setCSSClasses(array('fullwidth'));
|
||||
$row->add($skipButton, 12);
|
||||
}
|
||||
}
|
||||
$errorMessageDiv = new htmlDiv('generic-webauthn-error', new htmlOutputText(''));
|
||||
$errorMessageDiv->addDataAttribute('button', _('Ok'));
|
||||
$errorMessageDiv->addDataAttribute('title', _('Webauthn failed'));
|
||||
$row->add($errorMessageDiv, 12);
|
||||
$row->add(new htmlJavaScript('window.lam.webauthn.start(\'' . $pathPrefix . '\', ' . $selfServiceParam . ');'), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the webauthn manager.
|
||||
*
|
||||
* @return WebauthnManager manager
|
||||
*/
|
||||
public function getWebauthnManager() {
|
||||
return new WebauthnManager();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see \LAM\LIB\TWO_FACTOR\TwoFactorProvider::verify2ndFactor()
|
||||
*/
|
||||
public function verify2ndFactor($user, $password, $serial, $twoFactorInput) {
|
||||
logNewMessage(LOG_DEBUG, 'WebauthnProvider: Checking 2nd factor for ' . $user);
|
||||
include_once __DIR__ . '/webauthn.inc';
|
||||
$webauthnManager = $this->getWebauthnManager();
|
||||
if (!empty($_SESSION['ldap'])) {
|
||||
$userDn = $_SESSION['ldap']->getUserName();
|
||||
}
|
||||
else {
|
||||
$userDn = lamDecrypt($_SESSION['selfService_clientDN'], 'SelfService');
|
||||
}
|
||||
$hasTokens = $webauthnManager->isRegistered($userDn);
|
||||
if (!$hasTokens) {
|
||||
if ($this->config->twoFactorAuthenticationOptional && !$webauthnManager->isRegistered($user) && ($_POST['sig_response'] === 'skip')) {
|
||||
logNewMessage(LOG_DEBUG, 'Skipped 2FA for ' . $user . ' as no devices are registered and 2FA is optional.');
|
||||
return true;
|
||||
}
|
||||
$response = base64_decode($_POST['sig_response']);
|
||||
$registrationObject = PublicKeyCredentialCreationOptions::createFromString($_SESSION['webauthn_registration']);
|
||||
return $webauthnManager->storeNewRegistration($registrationObject, $response);
|
||||
}
|
||||
else {
|
||||
logNewMessage(LOG_DEBUG, 'Checking webauthn response of ' . $userDn);
|
||||
$response = base64_decode($_POST['sig_response']);
|
||||
return $webauthnManager->isValidAuthentication($response, $userDn);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the correct 2 factor provider.
|
||||
*/
|
||||
|
@ -486,6 +629,8 @@ class TwoFactorProviderService {
|
|||
const TWO_FACTOR_YUBICO = 'yubico';
|
||||
/** 2factor authentication via DUO */
|
||||
const TWO_FACTOR_DUO = 'duo';
|
||||
/** 2factor authentication via webauthn */
|
||||
const TWO_FACTOR_WEBAUTHN = 'webauthn';
|
||||
|
||||
private $config;
|
||||
|
||||
|
@ -520,6 +665,9 @@ class TwoFactorProviderService {
|
|||
elseif ($this->config->twoFactorAuthentication == TwoFactorProviderService::TWO_FACTOR_DUO) {
|
||||
return new DuoProvider($this->config);
|
||||
}
|
||||
elseif ($this->config->twoFactorAuthentication == TwoFactorProviderService::TWO_FACTOR_WEBAUTHN) {
|
||||
return new WebauthnProvider($this->config);
|
||||
}
|
||||
throw new \Exception('Invalid provider: ' . $this->config->twoFactorAuthentication);
|
||||
}
|
||||
|
||||
|
@ -534,6 +682,7 @@ class TwoFactorProviderService {
|
|||
$tfConfig->isSelfService = true;
|
||||
$tfConfig->twoFactorAuthentication = $profile->twoFactorAuthentication;
|
||||
$tfConfig->twoFactorAuthenticationInsecure = $profile->twoFactorAuthenticationInsecure;
|
||||
$tfConfig->twoFactorAuthenticationOptional = $profile->twoFactorAuthenticationOptional;
|
||||
if ($tfConfig->twoFactorAuthentication == TwoFactorProviderService::TWO_FACTOR_YUBICO) {
|
||||
$tfConfig->twoFactorAuthenticationURL = explode("\r\n", $profile->twoFactorAuthenticationURL);
|
||||
}
|
||||
|
@ -573,6 +722,7 @@ class TwoFactorProviderService {
|
|||
$tfConfig->isSelfService = false;
|
||||
$tfConfig->twoFactorAuthentication = $conf->getTwoFactorAuthentication();
|
||||
$tfConfig->twoFactorAuthenticationInsecure = $conf->getTwoFactorAuthenticationInsecure();
|
||||
$tfConfig->twoFactorAuthenticationOptional = $conf->getTwoFactorAuthenticationOptional();
|
||||
if ($tfConfig->twoFactorAuthentication == TwoFactorProviderService::TWO_FACTOR_YUBICO) {
|
||||
$tfConfig->twoFactorAuthenticationURL = explode("\r\n", $conf->getTwoFactorAuthenticationURL());
|
||||
}
|
||||
|
@ -641,4 +791,9 @@ class TwoFactorConfiguration {
|
|||
*/
|
||||
public $twoFactorAuthenticationSerialAttributeName = null;
|
||||
|
||||
/**
|
||||
* @var bool 2FA is optional
|
||||
*/
|
||||
public $twoFactorAuthenticationOptional = false;
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
|
||||
// autoload.php @generated by Composer
|
||||
|
||||
require_once __DIR__ . '/composer/autoload_real.php';
|
||||
|
||||
return ComposerAutoloaderInited73ceb9c1bdec18b7c6d09764d1bce5::getLoader();
|
|
@ -0,0 +1,11 @@
|
|||
Copyright (c) 2011-2013, Benjamin Eberlei
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
- Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
|
@ -0,0 +1,63 @@
|
|||
{
|
||||
"name": "beberlei/assert",
|
||||
"description": "Thin assertion library for input validation in business models.",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Benjamin Eberlei",
|
||||
"email": "kontakt@beberlei.de",
|
||||
"role": "Lead Developer"
|
||||
},
|
||||
{
|
||||
"name": "Richard Quadling",
|
||||
"email": "rquadling@gmail.com",
|
||||
"role": "Collaborator"
|
||||
}
|
||||
],
|
||||
"license": "BSD-2-Clause",
|
||||
"keywords": [
|
||||
"assert",
|
||||
"assertion",
|
||||
"validation"
|
||||
],
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Assert\\": "lib/Assert"
|
||||
},
|
||||
"files": [
|
||||
"lib/Assert/functions.php"
|
||||
]
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Assert\\Tests\\": "tests/Assert/Tests"
|
||||
},
|
||||
"files": [
|
||||
"tests/Assert/Tests/Fixtures/functions.php"
|
||||
]
|
||||
},
|
||||
"config": {
|
||||
"sort-packages": true
|
||||
},
|
||||
"require": {
|
||||
"php": "^7",
|
||||
"ext-simplexml": "*",
|
||||
"ext-mbstring": "*",
|
||||
"ext-ctype": "*",
|
||||
"ext-json": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "*",
|
||||
"phpstan/phpstan-shim": "*",
|
||||
"phpunit/phpunit": ">=6.0.0 <8"
|
||||
},
|
||||
"scripts": {
|
||||
"assert:generate-docs": "php bin/generate_method_docs.php",
|
||||
"assert:cs-lint": "php-cs-fixer fix --diff -vvv --dry-run",
|
||||
"assert:cs-fix": "php-cs-fixer fix . -vvv || true",
|
||||
"assert:sa-code": "vendor/bin/phpstan analyse --configuration=phpstan-code.neon --no-progress --ansi -l 7 bin lib",
|
||||
"assert:sa-tests": "vendor/bin/phpstan analyse --configuration=phpstan-tests.neon --no-progress --ansi -l 7 tests"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-intl": "Needed to allow Assertion::count(), Assertion::isCountable(), Assertion::minCount(), and Assertion::maxCount() to operate on ResourceBundles"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Assert
|
||||
*
|
||||
* LICENSE
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this package in the file LICENSE.txt.
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to kontakt@beberlei.de so I can send you a copy immediately.
|
||||
*/
|
||||
|
||||
namespace Assert;
|
||||
|
||||
/**
|
||||
* AssertionChain factory.
|
||||
*/
|
||||
abstract class Assert
|
||||
{
|
||||
/** @var string */
|
||||
protected static $lazyAssertionExceptionClass = LazyAssertionException::class;
|
||||
|
||||
/** @var string */
|
||||
protected static $assertionClass = Assertion::class;
|
||||
|
||||
/**
|
||||
* Start validation on a value, returns {@link AssertionChain}.
|
||||
*
|
||||
* The invocation of this method starts an assertion chain
|
||||
* that is happening on the passed value.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param string|callable|null $defaultMessage
|
||||
* @param string|null $defaultPropertyPath
|
||||
*
|
||||
* @return AssertionChain
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* Assert::that($value)->notEmpty()->integer();
|
||||
* Assert::that($value)->nullOr()->string()->startsWith("Foo");
|
||||
*
|
||||
* The assertion chain can be stateful, that means be careful when you reuse
|
||||
* it. You should never pass around the chain.
|
||||
*/
|
||||
public static function that($value, $defaultMessage = null, string $defaultPropertyPath = null): AssertionChain
|
||||
{
|
||||
$assertionChain = new AssertionChain($value, $defaultMessage, $defaultPropertyPath);
|
||||
|
||||
return $assertionChain->setAssertionClassName(static::$assertionClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start validation on a set of values, returns {@link AssertionChain}.
|
||||
*
|
||||
* @param mixed $values
|
||||
* @param string|callable|null $defaultMessage
|
||||
* @param string|null $defaultPropertyPath
|
||||
*
|
||||
* @return AssertionChain
|
||||
*/
|
||||
public static function thatAll($values, $defaultMessage = null, string $defaultPropertyPath = null): AssertionChain
|
||||
{
|
||||
return static::that($values, $defaultMessage, $defaultPropertyPath)->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start validation and allow NULL, returns {@link AssertionChain}.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param string|callable|null $defaultMessage
|
||||
* @param string|null $defaultPropertyPath
|
||||
*
|
||||
* @return AssertionChain
|
||||
*/
|
||||
public static function thatNullOr($value, $defaultMessage = null, string $defaultPropertyPath = null): AssertionChain
|
||||
{
|
||||
return static::that($value, $defaultMessage, $defaultPropertyPath)->nullOr();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a lazy assertion object.
|
||||
*
|
||||
* @return LazyAssertion
|
||||
*/
|
||||
public static function lazy(): LazyAssertion
|
||||
{
|
||||
$lazyAssertion = new LazyAssertion();
|
||||
|
||||
return $lazyAssertion
|
||||
->setAssertClass(\get_called_class())
|
||||
->setExceptionClass(static::$lazyAssertionExceptionClass);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,254 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Assert
|
||||
*
|
||||
* LICENSE
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this package in the file LICENSE.txt.
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to kontakt@beberlei.de so I can send you a copy immediately.
|
||||
*/
|
||||
|
||||
namespace Assert;
|
||||
|
||||
use LogicException;
|
||||
use ReflectionClass;
|
||||
|
||||
/**
|
||||
* Chaining builder for assertions.
|
||||
*
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
*
|
||||
* @method AssertionChain alnum(string|callable $message = null, string $propertyPath = null) Assert that value is alphanumeric.
|
||||
* @method AssertionChain base64(string|callable $message = null, string $propertyPath = null) Assert that a constant is defined.
|
||||
* @method AssertionChain between(mixed $lowerLimit, mixed $upperLimit, string|callable $message = null, string $propertyPath = null) Assert that a value is greater or equal than a lower limit, and less than or equal to an upper limit.
|
||||
* @method AssertionChain betweenExclusive(mixed $lowerLimit, mixed $upperLimit, string|callable $message = null, string $propertyPath = null) Assert that a value is greater than a lower limit, and less than an upper limit.
|
||||
* @method AssertionChain betweenLength(int $minLength, int $maxLength, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string length is between min and max lengths.
|
||||
* @method AssertionChain boolean(string|callable $message = null, string $propertyPath = null) Assert that value is php boolean.
|
||||
* @method AssertionChain choice(array $choices, string|callable $message = null, string $propertyPath = null) Assert that value is in array of choices.
|
||||
* @method AssertionChain choicesNotEmpty(array $choices, string|callable $message = null, string $propertyPath = null) Determines if the values array has every choice as key and that this choice has content.
|
||||
* @method AssertionChain classExists(string|callable $message = null, string $propertyPath = null) Assert that the class exists.
|
||||
* @method AssertionChain contains(string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string contains a sequence of chars.
|
||||
* @method AssertionChain count(int $count, string|callable $message = null, string $propertyPath = null) Assert that the count of countable is equal to count.
|
||||
* @method AssertionChain date(string $format, string|callable $message = null, string $propertyPath = null) Assert that date is valid and corresponds to the given format.
|
||||
* @method AssertionChain defined(string|callable $message = null, string $propertyPath = null) Assert that a constant is defined.
|
||||
* @method AssertionChain digit(string|callable $message = null, string $propertyPath = null) Validates if an integer or integerish is a digit.
|
||||
* @method AssertionChain directory(string|callable $message = null, string $propertyPath = null) Assert that a directory exists.
|
||||
* @method AssertionChain e164(string|callable $message = null, string $propertyPath = null) Assert that the given string is a valid E164 Phone Number.
|
||||
* @method AssertionChain email(string|callable $message = null, string $propertyPath = null) Assert that value is an email address (using input_filter/FILTER_VALIDATE_EMAIL).
|
||||
* @method AssertionChain endsWith(string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string ends with a sequence of chars.
|
||||
* @method AssertionChain eq(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are equal (using ==).
|
||||
* @method AssertionChain eqArraySubset(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that the array contains the subset.
|
||||
* @method AssertionChain extensionLoaded(string|callable $message = null, string $propertyPath = null) Assert that extension is loaded.
|
||||
* @method AssertionChain extensionVersion(string $operator, mixed $version, string|callable $message = null, string $propertyPath = null) Assert that extension is loaded and a specific version is installed.
|
||||
* @method AssertionChain false(string|callable $message = null, string $propertyPath = null) Assert that the value is boolean False.
|
||||
* @method AssertionChain file(string|callable $message = null, string $propertyPath = null) Assert that a file exists.
|
||||
* @method AssertionChain float(string|callable $message = null, string $propertyPath = null) Assert that value is a php float.
|
||||
* @method AssertionChain greaterOrEqualThan(mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is greater or equal than given limit.
|
||||
* @method AssertionChain greaterThan(mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is greater than given limit.
|
||||
* @method AssertionChain implementsInterface(string $interfaceName, string|callable $message = null, string $propertyPath = null) Assert that the class implements the interface.
|
||||
* @method AssertionChain inArray(array $choices, string|callable $message = null, string $propertyPath = null) Assert that value is in array of choices. This is an alias of Assertion::choice().
|
||||
* @method AssertionChain integer(string|callable $message = null, string $propertyPath = null) Assert that value is a php integer.
|
||||
* @method AssertionChain integerish(string|callable $message = null, string $propertyPath = null) Assert that value is a php integer'ish.
|
||||
* @method AssertionChain interfaceExists(string|callable $message = null, string $propertyPath = null) Assert that the interface exists.
|
||||
* @method AssertionChain ip(int $flag = null, string|callable $message = null, string $propertyPath = null) Assert that value is an IPv4 or IPv6 address.
|
||||
* @method AssertionChain ipv4(int $flag = null, string|callable $message = null, string $propertyPath = null) Assert that value is an IPv4 address.
|
||||
* @method AssertionChain ipv6(int $flag = null, string|callable $message = null, string $propertyPath = null) Assert that value is an IPv6 address.
|
||||
* @method AssertionChain isArray(string|callable $message = null, string $propertyPath = null) Assert that value is an array.
|
||||
* @method AssertionChain isArrayAccessible(string|callable $message = null, string $propertyPath = null) Assert that value is an array or an array-accessible object.
|
||||
* @method AssertionChain isCallable(string|callable $message = null, string $propertyPath = null) Determines that the provided value is callable.
|
||||
* @method AssertionChain isCountable(string|callable $message = null, string $propertyPath = null) Assert that value is countable.
|
||||
* @method AssertionChain isInstanceOf(string $className, string|callable $message = null, string $propertyPath = null) Assert that value is instance of given class-name.
|
||||
* @method AssertionChain isJsonString(string|callable $message = null, string $propertyPath = null) Assert that the given string is a valid json string.
|
||||
* @method AssertionChain isObject(string|callable $message = null, string $propertyPath = null) Determines that the provided value is an object.
|
||||
* @method AssertionChain isResource(string|callable $message = null, string $propertyPath = null) Assert that value is a resource.
|
||||
* @method AssertionChain isTraversable(string|callable $message = null, string $propertyPath = null) Assert that value is an array or a traversable object.
|
||||
* @method AssertionChain keyExists(string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key exists in an array.
|
||||
* @method AssertionChain keyIsset(string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key exists in an array/array-accessible object using isset().
|
||||
* @method AssertionChain keyNotExists(string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key does not exist in an array.
|
||||
* @method AssertionChain length(int $length, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string has a given length.
|
||||
* @method AssertionChain lessOrEqualThan(mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is less or equal than given limit.
|
||||
* @method AssertionChain lessThan(mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is less than given limit.
|
||||
* @method AssertionChain max(mixed $maxValue, string|callable $message = null, string $propertyPath = null) Assert that a number is smaller as a given limit.
|
||||
* @method AssertionChain maxCount(int $count, string|callable $message = null, string $propertyPath = null) Assert that the countable have at most $count elements.
|
||||
* @method AssertionChain maxLength(int $maxLength, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string value is not longer than $maxLength chars.
|
||||
* @method AssertionChain methodExists(mixed $object, string|callable $message = null, string $propertyPath = null) Determines that the named method is defined in the provided object.
|
||||
* @method AssertionChain min(mixed $minValue, string|callable $message = null, string $propertyPath = null) Assert that a value is at least as big as a given limit.
|
||||
* @method AssertionChain minCount(int $count, string|callable $message = null, string $propertyPath = null) Assert that the countable have at least $count elements.
|
||||
* @method AssertionChain minLength(int $minLength, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that a string is at least $minLength chars long.
|
||||
* @method AssertionChain noContent(string|callable $message = null, string $propertyPath = null) Assert that value is empty.
|
||||
* @method AssertionChain notBlank(string|callable $message = null, string $propertyPath = null) Assert that value is not blank.
|
||||
* @method AssertionChain notContains(string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string does not contains a sequence of chars.
|
||||
* @method AssertionChain notEmpty(string|callable $message = null, string $propertyPath = null) Assert that value is not empty.
|
||||
* @method AssertionChain notEmptyKey(string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key exists in an array/array-accessible object and its value is not empty.
|
||||
* @method AssertionChain notEq(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are not equal (using ==).
|
||||
* @method AssertionChain notInArray(array $choices, string|callable $message = null, string $propertyPath = null) Assert that value is not in array of choices.
|
||||
* @method AssertionChain notIsInstanceOf(string $className, string|callable $message = null, string $propertyPath = null) Assert that value is not instance of given class-name.
|
||||
* @method AssertionChain notNull(string|callable $message = null, string $propertyPath = null) Assert that value is not null.
|
||||
* @method AssertionChain notRegex(string $pattern, string|callable $message = null, string $propertyPath = null) Assert that value does not match a regex.
|
||||
* @method AssertionChain notSame(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are not the same (using ===).
|
||||
* @method AssertionChain null(string|callable $message = null, string $propertyPath = null) Assert that value is null.
|
||||
* @method AssertionChain numeric(string|callable $message = null, string $propertyPath = null) Assert that value is numeric.
|
||||
* @method AssertionChain objectOrClass(string|callable $message = null, string $propertyPath = null) Assert that the value is an object, or a class that exists.
|
||||
* @method AssertionChain phpVersion(mixed $version, string|callable $message = null, string $propertyPath = null) Assert on PHP version.
|
||||
* @method AssertionChain propertiesExist(array $properties, string|callable $message = null, string $propertyPath = null) Assert that the value is an object or class, and that the properties all exist.
|
||||
* @method AssertionChain propertyExists(string $property, string|callable $message = null, string $propertyPath = null) Assert that the value is an object or class, and that the property exists.
|
||||
* @method AssertionChain range(mixed $minValue, mixed $maxValue, string|callable $message = null, string $propertyPath = null) Assert that value is in range of numbers.
|
||||
* @method AssertionChain readable(string|callable $message = null, string $propertyPath = null) Assert that the value is something readable.
|
||||
* @method AssertionChain regex(string $pattern, string|callable $message = null, string $propertyPath = null) Assert that value matches a regex.
|
||||
* @method AssertionChain same(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are the same (using ===).
|
||||
* @method AssertionChain satisfy(callable $callback, string|callable $message = null, string $propertyPath = null) Assert that the provided value is valid according to a callback.
|
||||
* @method AssertionChain scalar(string|callable $message = null, string $propertyPath = null) Assert that value is a PHP scalar.
|
||||
* @method AssertionChain startsWith(string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string starts with a sequence of chars.
|
||||
* @method AssertionChain string(string|callable $message = null, string $propertyPath = null) Assert that value is a string.
|
||||
* @method AssertionChain subclassOf(string $className, string|callable $message = null, string $propertyPath = null) Assert that value is subclass of given class-name.
|
||||
* @method AssertionChain true(string|callable $message = null, string $propertyPath = null) Assert that the value is boolean True.
|
||||
* @method AssertionChain url(string|callable $message = null, string $propertyPath = null) Assert that value is an URL.
|
||||
* @method AssertionChain uuid(string|callable $message = null, string $propertyPath = null) Assert that the given string is a valid UUID.
|
||||
* @method AssertionChain version(string $operator, string $version2, string|callable $message = null, string $propertyPath = null) Assert comparison of two versions.
|
||||
* @method AssertionChain writeable(string|callable $message = null, string $propertyPath = null) Assert that the value is something writeable.
|
||||
*/
|
||||
class AssertionChain
|
||||
{
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
private $value;
|
||||
|
||||
/**
|
||||
* @var string|callable|null
|
||||
*/
|
||||
private $defaultMessage;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
private $defaultPropertyPath;
|
||||
|
||||
/**
|
||||
* Return each assertion as always valid.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $alwaysValid = false;
|
||||
|
||||
/**
|
||||
* Perform assertion on every element of array or traversable.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $all = false;
|
||||
|
||||
/** @var string|Assertion Class to use for assertion calls */
|
||||
private $assertionClassName = 'Assert\Assertion';
|
||||
|
||||
/**
|
||||
* AssertionChain constructor.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param string|callable|null $defaultMessage
|
||||
* @param string|null $defaultPropertyPath
|
||||
*/
|
||||
public function __construct($value, $defaultMessage = null, string $defaultPropertyPath = null)
|
||||
{
|
||||
$this->value = $value;
|
||||
$this->defaultMessage = $defaultMessage;
|
||||
$this->defaultPropertyPath = $defaultPropertyPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call assertion on the current value in the chain.
|
||||
*
|
||||
* @param string $methodName
|
||||
* @param array $args
|
||||
*
|
||||
* @return AssertionChain
|
||||
*/
|
||||
public function __call($methodName, $args): AssertionChain
|
||||
{
|
||||
if (true === $this->alwaysValid) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
if (!\method_exists($this->assertionClassName, $methodName)) {
|
||||
throw new \RuntimeException("Assertion '".$methodName."' does not exist.");
|
||||
}
|
||||
|
||||
$reflClass = new ReflectionClass($this->assertionClassName);
|
||||
$method = $reflClass->getMethod($methodName);
|
||||
|
||||
\array_unshift($args, $this->value);
|
||||
$params = $method->getParameters();
|
||||
|
||||
foreach ($params as $idx => $param) {
|
||||
if (isset($args[$idx])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ('message' == $param->getName()) {
|
||||
$args[$idx] = $this->defaultMessage;
|
||||
}
|
||||
|
||||
if ('propertyPath' == $param->getName()) {
|
||||
$args[$idx] = $this->defaultPropertyPath;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->all) {
|
||||
$methodName = 'all'.$methodName;
|
||||
}
|
||||
|
||||
\call_user_func_array([$this->assertionClassName, $methodName], $args);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch chain into validation mode for an array of values.
|
||||
*
|
||||
* @return AssertionChain
|
||||
*/
|
||||
public function all(): AssertionChain
|
||||
{
|
||||
$this->all = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch chain into mode allowing nulls, ignoring further assertions.
|
||||
*
|
||||
* @return AssertionChain
|
||||
*/
|
||||
public function nullOr(): AssertionChain
|
||||
{
|
||||
if (null === $this->value) {
|
||||
$this->alwaysValid = true;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $className
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setAssertionClassName($className): AssertionChain
|
||||
{
|
||||
if (!\is_string($className)) {
|
||||
throw new LogicException('Exception class name must be passed as a string');
|
||||
}
|
||||
|
||||
if (Assertion::class !== $className && !\is_subclass_of($className, Assertion::class)) {
|
||||
throw new LogicException($className.' is not (a subclass of) '.Assertion::class);
|
||||
}
|
||||
|
||||
$this->assertionClassName = $className;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
35
lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/AssertionFailedException.php
vendored
Normal file
35
lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/AssertionFailedException.php
vendored
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Assert
|
||||
*
|
||||
* LICENSE
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this package in the file LICENSE.txt.
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to kontakt@beberlei.de so I can send you a copy immediately.
|
||||
*/
|
||||
|
||||
namespace Assert;
|
||||
|
||||
use Throwable;
|
||||
|
||||
interface AssertionFailedException extends Throwable
|
||||
{
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getPropertyPath();
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getValue();
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getConstraints(): array;
|
||||
}
|
76
lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/InvalidArgumentException.php
vendored
Normal file
76
lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/InvalidArgumentException.php
vendored
Normal file
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Assert
|
||||
*
|
||||
* LICENSE
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this package in the file LICENSE.txt.
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to kontakt@beberlei.de so I can send you a copy immediately.
|
||||
*/
|
||||
|
||||
namespace Assert;
|
||||
|
||||
class InvalidArgumentException extends \InvalidArgumentException implements AssertionFailedException
|
||||
{
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
private $propertyPath;
|
||||
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
private $value;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $constraints;
|
||||
|
||||
public function __construct($message, $code, string $propertyPath = null, $value = null, array $constraints = [])
|
||||
{
|
||||
parent::__construct($message, $code);
|
||||
|
||||
$this->propertyPath = $propertyPath;
|
||||
$this->value = $value;
|
||||
$this->constraints = $constraints;
|
||||
}
|
||||
|
||||
/**
|
||||
* User controlled way to define a sub-property causing
|
||||
* the failure of a currently asserted objects.
|
||||
*
|
||||
* Useful to transport information about the nature of the error
|
||||
* back to higher layers.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getPropertyPath()
|
||||
{
|
||||
return $this->propertyPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value that caused the assertion to fail.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getValue()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the constraints that applied to the failed assertion.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getConstraints(): array
|
||||
{
|
||||
return $this->constraints;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,230 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Assert
|
||||
*
|
||||
* LICENSE
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this package in the file LICENSE.txt.
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to kontakt@beberlei.de so I can send you a copy immediately.
|
||||
*/
|
||||
|
||||
namespace Assert;
|
||||
|
||||
use LogicException;
|
||||
|
||||
/**
|
||||
* Chaining builder for lazy assertions.
|
||||
*
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
*
|
||||
* @method static static alnum(string|callable $message = null, string $propertyPath = null) Assert that value is alphanumeric.
|
||||
* @method static static base64(string|callable $message = null, string $propertyPath = null) Assert that a constant is defined.
|
||||
* @method static static between(mixed $lowerLimit, mixed $upperLimit, string|callable $message = null, string $propertyPath = null) Assert that a value is greater or equal than a lower limit, and less than or equal to an upper limit.
|
||||
* @method static static betweenExclusive(mixed $lowerLimit, mixed $upperLimit, string|callable $message = null, string $propertyPath = null) Assert that a value is greater than a lower limit, and less than an upper limit.
|
||||
* @method static static betweenLength(int $minLength, int $maxLength, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string length is between min and max lengths.
|
||||
* @method static static boolean(string|callable $message = null, string $propertyPath = null) Assert that value is php boolean.
|
||||
* @method static static choice(array $choices, string|callable $message = null, string $propertyPath = null) Assert that value is in array of choices.
|
||||
* @method static static choicesNotEmpty(array $choices, string|callable $message = null, string $propertyPath = null) Determines if the values array has every choice as key and that this choice has content.
|
||||
* @method static static classExists(string|callable $message = null, string $propertyPath = null) Assert that the class exists.
|
||||
* @method static static contains(string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string contains a sequence of chars.
|
||||
* @method static static count(int $count, string|callable $message = null, string $propertyPath = null) Assert that the count of countable is equal to count.
|
||||
* @method static static date(string $format, string|callable $message = null, string $propertyPath = null) Assert that date is valid and corresponds to the given format.
|
||||
* @method static static defined(string|callable $message = null, string $propertyPath = null) Assert that a constant is defined.
|
||||
* @method static static digit(string|callable $message = null, string $propertyPath = null) Validates if an integer or integerish is a digit.
|
||||
* @method static static directory(string|callable $message = null, string $propertyPath = null) Assert that a directory exists.
|
||||
* @method static static e164(string|callable $message = null, string $propertyPath = null) Assert that the given string is a valid E164 Phone Number.
|
||||
* @method static static email(string|callable $message = null, string $propertyPath = null) Assert that value is an email address (using input_filter/FILTER_VALIDATE_EMAIL).
|
||||
* @method static static endsWith(string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string ends with a sequence of chars.
|
||||
* @method static static eq(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are equal (using ==).
|
||||
* @method static static eqArraySubset(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that the array contains the subset.
|
||||
* @method static static extensionLoaded(string|callable $message = null, string $propertyPath = null) Assert that extension is loaded.
|
||||
* @method static static extensionVersion(string $operator, mixed $version, string|callable $message = null, string $propertyPath = null) Assert that extension is loaded and a specific version is installed.
|
||||
* @method static static false(string|callable $message = null, string $propertyPath = null) Assert that the value is boolean False.
|
||||
* @method static static file(string|callable $message = null, string $propertyPath = null) Assert that a file exists.
|
||||
* @method static static float(string|callable $message = null, string $propertyPath = null) Assert that value is a php float.
|
||||
* @method static static greaterOrEqualThan(mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is greater or equal than given limit.
|
||||
* @method static static greaterThan(mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is greater than given limit.
|
||||
* @method static static implementsInterface(string $interfaceName, string|callable $message = null, string $propertyPath = null) Assert that the class implements the interface.
|
||||
* @method static static inArray(array $choices, string|callable $message = null, string $propertyPath = null) Assert that value is in array of choices. This is an alias of Assertion::choice().
|
||||
* @method static static integer(string|callable $message = null, string $propertyPath = null) Assert that value is a php integer.
|
||||
* @method static static integerish(string|callable $message = null, string $propertyPath = null) Assert that value is a php integer'ish.
|
||||
* @method static static interfaceExists(string|callable $message = null, string $propertyPath = null) Assert that the interface exists.
|
||||
* @method static static ip(int $flag = null, string|callable $message = null, string $propertyPath = null) Assert that value is an IPv4 or IPv6 address.
|
||||
* @method static static ipv4(int $flag = null, string|callable $message = null, string $propertyPath = null) Assert that value is an IPv4 address.
|
||||
* @method static static ipv6(int $flag = null, string|callable $message = null, string $propertyPath = null) Assert that value is an IPv6 address.
|
||||
* @method static static isArray(string|callable $message = null, string $propertyPath = null) Assert that value is an array.
|
||||
* @method static static isArrayAccessible(string|callable $message = null, string $propertyPath = null) Assert that value is an array or an array-accessible object.
|
||||
* @method static static isCallable(string|callable $message = null, string $propertyPath = null) Determines that the provided value is callable.
|
||||
* @method static static isCountable(string|callable $message = null, string $propertyPath = null) Assert that value is countable.
|
||||
* @method static static isInstanceOf(string $className, string|callable $message = null, string $propertyPath = null) Assert that value is instance of given class-name.
|
||||
* @method static static isJsonString(string|callable $message = null, string $propertyPath = null) Assert that the given string is a valid json string.
|
||||
* @method static static isObject(string|callable $message = null, string $propertyPath = null) Determines that the provided value is an object.
|
||||
* @method static static isResource(string|callable $message = null, string $propertyPath = null) Assert that value is a resource.
|
||||
* @method static static isTraversable(string|callable $message = null, string $propertyPath = null) Assert that value is an array or a traversable object.
|
||||
* @method static static keyExists(string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key exists in an array.
|
||||
* @method static static keyIsset(string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key exists in an array/array-accessible object using isset().
|
||||
* @method static static keyNotExists(string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key does not exist in an array.
|
||||
* @method static static length(int $length, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string has a given length.
|
||||
* @method static static lessOrEqualThan(mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is less or equal than given limit.
|
||||
* @method static static lessThan(mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is less than given limit.
|
||||
* @method static static max(mixed $maxValue, string|callable $message = null, string $propertyPath = null) Assert that a number is smaller as a given limit.
|
||||
* @method static static maxCount(int $count, string|callable $message = null, string $propertyPath = null) Assert that the countable have at most $count elements.
|
||||
* @method static static maxLength(int $maxLength, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string value is not longer than $maxLength chars.
|
||||
* @method static static methodExists(mixed $object, string|callable $message = null, string $propertyPath = null) Determines that the named method is defined in the provided object.
|
||||
* @method static static min(mixed $minValue, string|callable $message = null, string $propertyPath = null) Assert that a value is at least as big as a given limit.
|
||||
* @method static static minCount(int $count, string|callable $message = null, string $propertyPath = null) Assert that the countable have at least $count elements.
|
||||
* @method static static minLength(int $minLength, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that a string is at least $minLength chars long.
|
||||
* @method static static noContent(string|callable $message = null, string $propertyPath = null) Assert that value is empty.
|
||||
* @method static static notBlank(string|callable $message = null, string $propertyPath = null) Assert that value is not blank.
|
||||
* @method static static notContains(string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string does not contains a sequence of chars.
|
||||
* @method static static notEmpty(string|callable $message = null, string $propertyPath = null) Assert that value is not empty.
|
||||
* @method static static notEmptyKey(string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key exists in an array/array-accessible object and its value is not empty.
|
||||
* @method static static notEq(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are not equal (using ==).
|
||||
* @method static static notInArray(array $choices, string|callable $message = null, string $propertyPath = null) Assert that value is not in array of choices.
|
||||
* @method static static notIsInstanceOf(string $className, string|callable $message = null, string $propertyPath = null) Assert that value is not instance of given class-name.
|
||||
* @method static static notNull(string|callable $message = null, string $propertyPath = null) Assert that value is not null.
|
||||
* @method static static notRegex(string $pattern, string|callable $message = null, string $propertyPath = null) Assert that value does not match a regex.
|
||||
* @method static static notSame(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are not the same (using ===).
|
||||
* @method static static null(string|callable $message = null, string $propertyPath = null) Assert that value is null.
|
||||
* @method static static numeric(string|callable $message = null, string $propertyPath = null) Assert that value is numeric.
|
||||
* @method static static objectOrClass(string|callable $message = null, string $propertyPath = null) Assert that the value is an object, or a class that exists.
|
||||
* @method static static phpVersion(mixed $version, string|callable $message = null, string $propertyPath = null) Assert on PHP version.
|
||||
* @method static static propertiesExist(array $properties, string|callable $message = null, string $propertyPath = null) Assert that the value is an object or class, and that the properties all exist.
|
||||
* @method static static propertyExists(string $property, string|callable $message = null, string $propertyPath = null) Assert that the value is an object or class, and that the property exists.
|
||||
* @method static static range(mixed $minValue, mixed $maxValue, string|callable $message = null, string $propertyPath = null) Assert that value is in range of numbers.
|
||||
* @method static static readable(string|callable $message = null, string $propertyPath = null) Assert that the value is something readable.
|
||||
* @method static static regex(string $pattern, string|callable $message = null, string $propertyPath = null) Assert that value matches a regex.
|
||||
* @method static static same(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are the same (using ===).
|
||||
* @method static static satisfy(callable $callback, string|callable $message = null, string $propertyPath = null) Assert that the provided value is valid according to a callback.
|
||||
* @method static static scalar(string|callable $message = null, string $propertyPath = null) Assert that value is a PHP scalar.
|
||||
* @method static static startsWith(string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string starts with a sequence of chars.
|
||||
* @method static static string(string|callable $message = null, string $propertyPath = null) Assert that value is a string.
|
||||
* @method static static subclassOf(string $className, string|callable $message = null, string $propertyPath = null) Assert that value is subclass of given class-name.
|
||||
* @method static static true(string|callable $message = null, string $propertyPath = null) Assert that the value is boolean True.
|
||||
* @method static static url(string|callable $message = null, string $propertyPath = null) Assert that value is an URL.
|
||||
* @method static static uuid(string|callable $message = null, string $propertyPath = null) Assert that the given string is a valid UUID.
|
||||
* @method static static version(string $operator, string $version2, string|callable $message = null, string $propertyPath = null) Assert comparison of two versions.
|
||||
* @method static static writeable(string|callable $message = null, string $propertyPath = null) Assert that the value is something writeable.
|
||||
* @method static static all() Switch chain into validation mode for an array of values.
|
||||
* @method static static nullOr() Switch chain into mode allowing nulls, ignoring further assertions.
|
||||
*/
|
||||
class LazyAssertion
|
||||
{
|
||||
private $currentChainFailed = false;
|
||||
private $alwaysTryAll = false;
|
||||
private $thisChainTryAll = false;
|
||||
private $currentChain;
|
||||
private $errors = [];
|
||||
|
||||
/** @var string The class to use as AssertionChain factory */
|
||||
private $assertClass = Assert::class;
|
||||
|
||||
/** @var string|LazyAssertionException The class to use for exceptions */
|
||||
private $exceptionClass = LazyAssertionException::class;
|
||||
|
||||
/**
|
||||
* @param mixed $value
|
||||
* @param string|null $propertyPath
|
||||
* @param string|callable|null $defaultMessage
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function that($value, string $propertyPath = null, $defaultMessage = null)
|
||||
{
|
||||
$this->currentChainFailed = false;
|
||||
$this->thisChainTryAll = false;
|
||||
$assertClass = $this->assertClass;
|
||||
$this->currentChain = $assertClass::that($value, $defaultMessage, $propertyPath);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return static
|
||||
*/
|
||||
public function tryAll()
|
||||
{
|
||||
if (!$this->currentChain) {
|
||||
$this->alwaysTryAll = true;
|
||||
}
|
||||
|
||||
$this->thisChainTryAll = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $method
|
||||
* @param array $args
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function __call($method, $args)
|
||||
{
|
||||
if (false === $this->alwaysTryAll
|
||||
&& false === $this->thisChainTryAll
|
||||
&& true === $this->currentChainFailed
|
||||
) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
try {
|
||||
\call_user_func_array([$this->currentChain, $method], $args);
|
||||
} catch (AssertionFailedException $e) {
|
||||
$this->errors[] = $e;
|
||||
$this->currentChainFailed = true;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*
|
||||
* @throws LazyAssertionException
|
||||
*/
|
||||
public function verifyNow(): bool
|
||||
{
|
||||
if ($this->errors) {
|
||||
throw \call_user_func([$this->exceptionClass, 'fromErrors'], $this->errors);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $className
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function setAssertClass(string $className)
|
||||
{
|
||||
if (Assert::class !== $className && !\is_subclass_of($className, Assert::class)) {
|
||||
throw new LogicException($className.' is not (a subclass of) '.Assert::class);
|
||||
}
|
||||
|
||||
$this->assertClass = $className;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $className
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function setExceptionClass(string $className)
|
||||
{
|
||||
if (LazyAssertionException::class !== $className && !\is_subclass_of($className, LazyAssertionException::class)) {
|
||||
throw new LogicException($className.' is not (a subclass of) '.LazyAssertionException::class);
|
||||
}
|
||||
|
||||
$this->exceptionClass = $className;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
55
lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/LazyAssertionException.php
vendored
Normal file
55
lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/LazyAssertionException.php
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Assert
|
||||
*
|
||||
* LICENSE
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this package in the file LICENSE.txt.
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to kontakt@beberlei.de so I can send you a copy immediately.
|
||||
*/
|
||||
|
||||
namespace Assert;
|
||||
|
||||
class LazyAssertionException extends InvalidArgumentException
|
||||
{
|
||||
/**
|
||||
* @var InvalidArgumentException[]
|
||||
*/
|
||||
private $errors = [];
|
||||
|
||||
/**
|
||||
* @param InvalidArgumentException[] $errors
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public static function fromErrors(array $errors): self
|
||||
{
|
||||
$message = \sprintf('The following %d assertions failed:', \count($errors))."\n";
|
||||
|
||||
$i = 1;
|
||||
foreach ($errors as $error) {
|
||||
$message .= \sprintf("%d) %s: %s\n", $i++, $error->getPropertyPath(), $error->getMessage());
|
||||
}
|
||||
|
||||
return new static($message, $errors);
|
||||
}
|
||||
|
||||
public function __construct($message, array $errors)
|
||||
{
|
||||
parent::__construct($message, 0, null, null);
|
||||
|
||||
$this->errors = $errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return InvalidArgumentException[]
|
||||
*/
|
||||
public function getErrorExceptions(): array
|
||||
{
|
||||
return $this->errors;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Assert
|
||||
*
|
||||
* LICENSE
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this package in the file LICENSE.txt.
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to kontakt@beberlei.de so I can send you a copy immediately.
|
||||
*/
|
||||
|
||||
namespace Assert;
|
||||
|
||||
/**
|
||||
* Start validation on a value, returns {@link AssertionChain}.
|
||||
*
|
||||
* The invocation of this method starts an assertion chain
|
||||
* that is happening on the passed value.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param string|callable|null $defaultMessage
|
||||
* @param string $defaultPropertyPath
|
||||
*
|
||||
* @return AssertionChain
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* \Assert\that($value)->notEmpty()->integer();
|
||||
* \Assert\that($value)->nullOr()->string()->startsWith("Foo");
|
||||
*
|
||||
* The assertion chain can be stateful, that means be careful when you reuse
|
||||
* it. You should never pass around the chain.
|
||||
*/
|
||||
function that($value, $defaultMessage = null, string $defaultPropertyPath = null): AssertionChain
|
||||
{
|
||||
return Assert::that($value, $defaultMessage, $defaultPropertyPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start validation on a set of values, returns {@link AssertionChain}.
|
||||
*
|
||||
* @param mixed $values
|
||||
* @param string|callable|null $defaultMessage
|
||||
* @param string $defaultPropertyPath
|
||||
*
|
||||
* @return AssertionChain
|
||||
*/
|
||||
function thatAll($values, $defaultMessage = null, string $defaultPropertyPath = null): AssertionChain
|
||||
{
|
||||
return Assert::thatAll($values, $defaultMessage, $defaultPropertyPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start validation and allow NULL, returns {@link AssertionChain}.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param string|callable|null $defaultMessage
|
||||
* @param string $defaultPropertyPath
|
||||
*
|
||||
* @return AssertionChain
|
||||
*
|
||||
* @deprecated In favour of Assert::thatNullOr($value, $defaultMessage = null, $defaultPropertyPath = null)
|
||||
*/
|
||||
function thatNullOr($value, $defaultMessage = null, string $defaultPropertyPath = null): AssertionChain
|
||||
{
|
||||
return Assert::thatNullOr($value, $defaultMessage, $defaultPropertyPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a lazy assertion object.
|
||||
*
|
||||
* @return LazyAssertion
|
||||
*/
|
||||
function lazy(): LazyAssertion
|
||||
{
|
||||
return Assert::lazy();
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
parameters:
|
||||
autoload_files:
|
||||
- bin/MethodDocGenerator.php
|
||||
ignoreErrors:
|
||||
# is_countable() is available only in PHP 7.3+
|
||||
- '#Function is_countable not found#'
|
||||
|
||||
# Calling count() on ResourceBundle and SimpleXMLElement is valid from PHP 7.0+, but does not correctly advertise
|
||||
# the fact, and so PHPStan has an issue with this. This will be fixed in PHP 7.4+
|
||||
- '#Call to function count\(\) with argument type array|Countable|ResourceBundle|SimpleXMLElement will always result in number 1#'
|
|
@ -0,0 +1,10 @@
|
|||
parameters:
|
||||
ignoreErrors:
|
||||
# The following errors are ignored as they are testing for errors and exceptions that static analysis correctly identifies as problems.
|
||||
- '#Call to an undefined method Assert\\AssertionChain::unknownAssertion\(\)#'
|
||||
- '#Call to an undefined static method Assert\\Assertion::nullOrAssertionDoesNotExist\(\)#'
|
||||
- '#Class Foo not found#'
|
||||
- '#Parameter \#1 $value of static method Assert\\Assertion::isCountable\(\) expects array|Countable|ResourceBundle|SimpleXMLElement, string given#'
|
||||
- '#Parameter \#2 \$operator of static method Assert\\Assertion::version\(\) expects string, null given#'
|
||||
- '#Static method Assert\\Assertion::allTrue\(\) invoked with 0 parameters, 1-3 required#'
|
||||
- '#Static method Assert\\Assertion::nullOrMax\(\) invoked with 0 parameters, 2-4 required#'
|
|
@ -0,0 +1,445 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer\Autoload;
|
||||
|
||||
/**
|
||||
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
|
||||
*
|
||||
* $loader = new \Composer\Autoload\ClassLoader();
|
||||
*
|
||||
* // register classes with namespaces
|
||||
* $loader->add('Symfony\Component', __DIR__.'/component');
|
||||
* $loader->add('Symfony', __DIR__.'/framework');
|
||||
*
|
||||
* // activate the autoloader
|
||||
* $loader->register();
|
||||
*
|
||||
* // to enable searching the include path (eg. for PEAR packages)
|
||||
* $loader->setUseIncludePath(true);
|
||||
*
|
||||
* In this example, if you try to use a class in the Symfony\Component
|
||||
* namespace or one of its children (Symfony\Component\Console for instance),
|
||||
* the autoloader will first look for the class under the component/
|
||||
* directory, and it will then fallback to the framework/ directory if not
|
||||
* found before giving up.
|
||||
*
|
||||
* This class is loosely based on the Symfony UniversalClassLoader.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
* @see http://www.php-fig.org/psr/psr-0/
|
||||
* @see http://www.php-fig.org/psr/psr-4/
|
||||
*/
|
||||
class ClassLoader
|
||||
{
|
||||
// PSR-4
|
||||
private $prefixLengthsPsr4 = array();
|
||||
private $prefixDirsPsr4 = array();
|
||||
private $fallbackDirsPsr4 = array();
|
||||
|
||||
// PSR-0
|
||||
private $prefixesPsr0 = array();
|
||||
private $fallbackDirsPsr0 = array();
|
||||
|
||||
private $useIncludePath = false;
|
||||
private $classMap = array();
|
||||
private $classMapAuthoritative = false;
|
||||
private $missingClasses = array();
|
||||
private $apcuPrefix;
|
||||
|
||||
public function getPrefixes()
|
||||
{
|
||||
if (!empty($this->prefixesPsr0)) {
|
||||
return call_user_func_array('array_merge', $this->prefixesPsr0);
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
public function getPrefixesPsr4()
|
||||
{
|
||||
return $this->prefixDirsPsr4;
|
||||
}
|
||||
|
||||
public function getFallbackDirs()
|
||||
{
|
||||
return $this->fallbackDirsPsr0;
|
||||
}
|
||||
|
||||
public function getFallbackDirsPsr4()
|
||||
{
|
||||
return $this->fallbackDirsPsr4;
|
||||
}
|
||||
|
||||
public function getClassMap()
|
||||
{
|
||||
return $this->classMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $classMap Class to filename map
|
||||
*/
|
||||
public function addClassMap(array $classMap)
|
||||
{
|
||||
if ($this->classMap) {
|
||||
$this->classMap = array_merge($this->classMap, $classMap);
|
||||
} else {
|
||||
$this->classMap = $classMap;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-0 directories for a given prefix, either
|
||||
* appending or prepending to the ones previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param array|string $paths The PSR-0 root directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*/
|
||||
public function add($prefix, $paths, $prepend = false)
|
||||
{
|
||||
if (!$prefix) {
|
||||
if ($prepend) {
|
||||
$this->fallbackDirsPsr0 = array_merge(
|
||||
(array) $paths,
|
||||
$this->fallbackDirsPsr0
|
||||
);
|
||||
} else {
|
||||
$this->fallbackDirsPsr0 = array_merge(
|
||||
$this->fallbackDirsPsr0,
|
||||
(array) $paths
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$first = $prefix[0];
|
||||
if (!isset($this->prefixesPsr0[$first][$prefix])) {
|
||||
$this->prefixesPsr0[$first][$prefix] = (array) $paths;
|
||||
|
||||
return;
|
||||
}
|
||||
if ($prepend) {
|
||||
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||
(array) $paths,
|
||||
$this->prefixesPsr0[$first][$prefix]
|
||||
);
|
||||
} else {
|
||||
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||
$this->prefixesPsr0[$first][$prefix],
|
||||
(array) $paths
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-4 directories for a given namespace, either
|
||||
* appending or prepending to the ones previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param array|string $paths The PSR-4 base directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function addPsr4($prefix, $paths, $prepend = false)
|
||||
{
|
||||
if (!$prefix) {
|
||||
// Register directories for the root namespace.
|
||||
if ($prepend) {
|
||||
$this->fallbackDirsPsr4 = array_merge(
|
||||
(array) $paths,
|
||||
$this->fallbackDirsPsr4
|
||||
);
|
||||
} else {
|
||||
$this->fallbackDirsPsr4 = array_merge(
|
||||
$this->fallbackDirsPsr4,
|
||||
(array) $paths
|
||||
);
|
||||
}
|
||||
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
|
||||
// Register directories for a new namespace.
|
||||
$length = strlen($prefix);
|
||||
if ('\\' !== $prefix[$length - 1]) {
|
||||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||
}
|
||||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
||||
} elseif ($prepend) {
|
||||
// Prepend directories for an already registered namespace.
|
||||
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||
(array) $paths,
|
||||
$this->prefixDirsPsr4[$prefix]
|
||||
);
|
||||
} else {
|
||||
// Append directories for an already registered namespace.
|
||||
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||
$this->prefixDirsPsr4[$prefix],
|
||||
(array) $paths
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-0 directories for a given prefix,
|
||||
* replacing any others previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param array|string $paths The PSR-0 base directories
|
||||
*/
|
||||
public function set($prefix, $paths)
|
||||
{
|
||||
if (!$prefix) {
|
||||
$this->fallbackDirsPsr0 = (array) $paths;
|
||||
} else {
|
||||
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-4 directories for a given namespace,
|
||||
* replacing any others previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param array|string $paths The PSR-4 base directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function setPsr4($prefix, $paths)
|
||||
{
|
||||
if (!$prefix) {
|
||||
$this->fallbackDirsPsr4 = (array) $paths;
|
||||
} else {
|
||||
$length = strlen($prefix);
|
||||
if ('\\' !== $prefix[$length - 1]) {
|
||||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||
}
|
||||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns on searching the include path for class files.
|
||||
*
|
||||
* @param bool $useIncludePath
|
||||
*/
|
||||
public function setUseIncludePath($useIncludePath)
|
||||
{
|
||||
$this->useIncludePath = $useIncludePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be used to check if the autoloader uses the include path to check
|
||||
* for classes.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getUseIncludePath()
|
||||
{
|
||||
return $this->useIncludePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns off searching the prefix and fallback directories for classes
|
||||
* that have not been registered with the class map.
|
||||
*
|
||||
* @param bool $classMapAuthoritative
|
||||
*/
|
||||
public function setClassMapAuthoritative($classMapAuthoritative)
|
||||
{
|
||||
$this->classMapAuthoritative = $classMapAuthoritative;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should class lookup fail if not found in the current class map?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isClassMapAuthoritative()
|
||||
{
|
||||
return $this->classMapAuthoritative;
|
||||
}
|
||||
|
||||
/**
|
||||
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
|
||||
*
|
||||
* @param string|null $apcuPrefix
|
||||
*/
|
||||
public function setApcuPrefix($apcuPrefix)
|
||||
{
|
||||
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The APCu prefix in use, or null if APCu caching is not enabled.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getApcuPrefix()
|
||||
{
|
||||
return $this->apcuPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers this instance as an autoloader.
|
||||
*
|
||||
* @param bool $prepend Whether to prepend the autoloader or not
|
||||
*/
|
||||
public function register($prepend = false)
|
||||
{
|
||||
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters this instance as an autoloader.
|
||||
*/
|
||||
public function unregister()
|
||||
{
|
||||
spl_autoload_unregister(array($this, 'loadClass'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the given class or interface.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
* @return bool|null True if loaded, null otherwise
|
||||
*/
|
||||
public function loadClass($class)
|
||||
{
|
||||
if ($file = $this->findFile($class)) {
|
||||
includeFile($file);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the path to the file where the class is defined.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
*
|
||||
* @return string|false The path if found, false otherwise
|
||||
*/
|
||||
public function findFile($class)
|
||||
{
|
||||
// class map lookup
|
||||
if (isset($this->classMap[$class])) {
|
||||
return $this->classMap[$class];
|
||||
}
|
||||
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
|
||||
return false;
|
||||
}
|
||||
if (null !== $this->apcuPrefix) {
|
||||
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
|
||||
if ($hit) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
$file = $this->findFileWithExtension($class, '.php');
|
||||
|
||||
// Search for Hack files if we are running on HHVM
|
||||
if (false === $file && defined('HHVM_VERSION')) {
|
||||
$file = $this->findFileWithExtension($class, '.hh');
|
||||
}
|
||||
|
||||
if (null !== $this->apcuPrefix) {
|
||||
apcu_add($this->apcuPrefix.$class, $file);
|
||||
}
|
||||
|
||||
if (false === $file) {
|
||||
// Remember that this class does not exist.
|
||||
$this->missingClasses[$class] = true;
|
||||
}
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
private function findFileWithExtension($class, $ext)
|
||||
{
|
||||
// PSR-4 lookup
|
||||
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
|
||||
|
||||
$first = $class[0];
|
||||
if (isset($this->prefixLengthsPsr4[$first])) {
|
||||
$subPath = $class;
|
||||
while (false !== $lastPos = strrpos($subPath, '\\')) {
|
||||
$subPath = substr($subPath, 0, $lastPos);
|
||||
$search = $subPath . '\\';
|
||||
if (isset($this->prefixDirsPsr4[$search])) {
|
||||
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
|
||||
foreach ($this->prefixDirsPsr4[$search] as $dir) {
|
||||
if (file_exists($file = $dir . $pathEnd)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-4 fallback dirs
|
||||
foreach ($this->fallbackDirsPsr4 as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 lookup
|
||||
if (false !== $pos = strrpos($class, '\\')) {
|
||||
// namespaced class name
|
||||
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
|
||||
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
|
||||
} else {
|
||||
// PEAR-like class name
|
||||
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
|
||||
}
|
||||
|
||||
if (isset($this->prefixesPsr0[$first])) {
|
||||
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
|
||||
if (0 === strpos($class, $prefix)) {
|
||||
foreach ($dirs as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 fallback dirs
|
||||
foreach ($this->fallbackDirsPsr0 as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 include paths.
|
||||
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope isolated include.
|
||||
*
|
||||
* Prevents access to $this/self from included files.
|
||||
*/
|
||||
function includeFile($file)
|
||||
{
|
||||
include $file;
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: Composer
|
||||
Upstream-Contact: Jordi Boggiano <j.boggiano@seld.be>
|
||||
Source: https://github.com/composer/composer
|
||||
|
||||
Files: *
|
||||
Copyright: 2016, Nils Adermann <naderman@naderman.de>
|
||||
2016, Jordi Boggiano <j.boggiano@seld.be>
|
||||
License: Expat
|
||||
|
||||
Files: src/Composer/Util/TlsHelper.php
|
||||
Copyright: 2016, Nils Adermann <naderman@naderman.de>
|
||||
2016, Jordi Boggiano <j.boggiano@seld.be>
|
||||
2013, Evan Coury <me@evancoury.com>
|
||||
License: Expat and BSD-2-Clause
|
||||
|
||||
License: BSD-2-Clause
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
.
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
.
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
License: Expat
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
.
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
// autoload_classmap.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(dirname(__FILE__));
|
||||
$baseDir = dirname(dirname(dirname($vendorDir)));
|
||||
|
||||
return array(
|
||||
);
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
// autoload_files.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(dirname(__FILE__));
|
||||
$baseDir = dirname(dirname(dirname($vendorDir)));
|
||||
|
||||
return array(
|
||||
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
|
||||
'a4ecaeafb8cfb009ad0e052c90355e98' => $vendorDir . '/beberlei/assert/lib/Assert/functions.php',
|
||||
'25072dd6e2470089de65ae7bf11d3109' => $vendorDir . '/symfony/polyfill-php72/bootstrap.php',
|
||||
'f598d06aa772fa33d905e87be6398fb1' => $vendorDir . '/symfony/polyfill-intl-idn/bootstrap.php',
|
||||
'320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
|
||||
);
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
// autoload_namespaces.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(dirname(__FILE__));
|
||||
$baseDir = dirname(dirname(dirname($vendorDir)));
|
||||
|
||||
return array(
|
||||
);
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
// autoload_psr4.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(dirname(__FILE__));
|
||||
$baseDir = dirname(dirname(dirname($vendorDir)));
|
||||
|
||||
return array(
|
||||
'Webauthn\\MetadataService\\' => array($vendorDir . '/web-auth/metadata-service/src'),
|
||||
'Webauthn\\' => array($vendorDir . '/web-auth/webauthn-lib/src'),
|
||||
'Symfony\\Polyfill\\Php72\\' => array($vendorDir . '/symfony/polyfill-php72'),
|
||||
'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
|
||||
'Symfony\\Polyfill\\Intl\\Idn\\' => array($vendorDir . '/symfony/polyfill-intl-idn'),
|
||||
'Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'),
|
||||
'Symfony\\Component\\Mime\\' => array($vendorDir . '/symfony/mime'),
|
||||
'Symfony\\Component\\HttpFoundation\\' => array($vendorDir . '/symfony/http-foundation'),
|
||||
'Symfony\\Bridge\\PsrHttpMessage\\' => array($vendorDir . '/symfony/psr-http-message-bridge'),
|
||||
'Ramsey\\Uuid\\' => array($vendorDir . '/ramsey/uuid/src'),
|
||||
'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-factory/src', $vendorDir . '/psr/http-message/src'),
|
||||
'Psr\\Http\\Client\\' => array($vendorDir . '/psr/http-client/src'),
|
||||
'Nyholm\\Psr7\\' => array($vendorDir . '/nyholm/psr7/src'),
|
||||
'Http\\Message\\' => array($vendorDir . '/php-http/message-factory/src'),
|
||||
'FG\\' => array($vendorDir . '/fgrosse/phpasn1/lib'),
|
||||
'Cose\\' => array($vendorDir . '/web-auth/cose-lib/src'),
|
||||
'CBOR\\' => array($vendorDir . '/spomky-labs/cbor-php/src'),
|
||||
'Base64Url\\' => array($vendorDir . '/spomky-labs/base64url/src'),
|
||||
'Assert\\' => array($vendorDir . '/beberlei/assert/lib/Assert'),
|
||||
);
|
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
|
||||
// autoload_real.php @generated by Composer
|
||||
|
||||
class ComposerAutoloaderInited73ceb9c1bdec18b7c6d09764d1bce5
|
||||
{
|
||||
private static $loader;
|
||||
|
||||
public static function loadClassLoader($class)
|
||||
{
|
||||
if ('Composer\Autoload\ClassLoader' === $class) {
|
||||
require __DIR__ . '/ClassLoader.php';
|
||||
}
|
||||
}
|
||||
|
||||
public static function getLoader()
|
||||
{
|
||||
if (null !== self::$loader) {
|
||||
return self::$loader;
|
||||
}
|
||||
|
||||
spl_autoload_register(array('ComposerAutoloaderInited73ceb9c1bdec18b7c6d09764d1bce5', 'loadClassLoader'), true, true);
|
||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
|
||||
spl_autoload_unregister(array('ComposerAutoloaderInited73ceb9c1bdec18b7c6d09764d1bce5', 'loadClassLoader'));
|
||||
|
||||
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
|
||||
if ($useStaticLoader) {
|
||||
require_once __DIR__ . '/autoload_static.php';
|
||||
|
||||
call_user_func(\Composer\Autoload\ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5::getInitializer($loader));
|
||||
} else {
|
||||
$map = require __DIR__ . '/autoload_namespaces.php';
|
||||
foreach ($map as $namespace => $path) {
|
||||
$loader->set($namespace, $path);
|
||||
}
|
||||
|
||||
$map = require __DIR__ . '/autoload_psr4.php';
|
||||
foreach ($map as $namespace => $path) {
|
||||
$loader->setPsr4($namespace, $path);
|
||||
}
|
||||
|
||||
$classMap = require __DIR__ . '/autoload_classmap.php';
|
||||
if ($classMap) {
|
||||
$loader->addClassMap($classMap);
|
||||
}
|
||||
}
|
||||
|
||||
$loader->register(true);
|
||||
|
||||
if ($useStaticLoader) {
|
||||
$includeFiles = Composer\Autoload\ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5::$files;
|
||||
} else {
|
||||
$includeFiles = require __DIR__ . '/autoload_files.php';
|
||||
}
|
||||
foreach ($includeFiles as $fileIdentifier => $file) {
|
||||
composerRequireed73ceb9c1bdec18b7c6d09764d1bce5($fileIdentifier, $file);
|
||||
}
|
||||
|
||||
return $loader;
|
||||
}
|
||||
}
|
||||
|
||||
function composerRequireed73ceb9c1bdec18b7c6d09764d1bce5($fileIdentifier, $file)
|
||||
{
|
||||
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
|
||||
require $file;
|
||||
|
||||
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
<?php
|
||||
|
||||
// autoload_static.php @generated by Composer
|
||||
|
||||
namespace Composer\Autoload;
|
||||
|
||||
class ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5
|
||||
{
|
||||
public static $files = array (
|
||||
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
|
||||
'a4ecaeafb8cfb009ad0e052c90355e98' => __DIR__ . '/..' . '/beberlei/assert/lib/Assert/functions.php',
|
||||
'25072dd6e2470089de65ae7bf11d3109' => __DIR__ . '/..' . '/symfony/polyfill-php72/bootstrap.php',
|
||||
'f598d06aa772fa33d905e87be6398fb1' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/bootstrap.php',
|
||||
'320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
|
||||
);
|
||||
|
||||
public static $prefixLengthsPsr4 = array (
|
||||
'W' =>
|
||||
array (
|
||||
'Webauthn\\MetadataService\\' => 25,
|
||||
'Webauthn\\' => 9,
|
||||
),
|
||||
'S' =>
|
||||
array (
|
||||
'Symfony\\Polyfill\\Php72\\' => 23,
|
||||
'Symfony\\Polyfill\\Mbstring\\' => 26,
|
||||
'Symfony\\Polyfill\\Intl\\Idn\\' => 26,
|
||||
'Symfony\\Polyfill\\Ctype\\' => 23,
|
||||
'Symfony\\Component\\Mime\\' => 23,
|
||||
'Symfony\\Component\\HttpFoundation\\' => 33,
|
||||
'Symfony\\Bridge\\PsrHttpMessage\\' => 30,
|
||||
),
|
||||
'R' =>
|
||||
array (
|
||||
'Ramsey\\Uuid\\' => 12,
|
||||
),
|
||||
'P' =>
|
||||
array (
|
||||
'Psr\\Http\\Message\\' => 17,
|
||||
'Psr\\Http\\Client\\' => 16,
|
||||
),
|
||||
'N' =>
|
||||
array (
|
||||
'Nyholm\\Psr7\\' => 12,
|
||||
),
|
||||
'H' =>
|
||||
array (
|
||||
'Http\\Message\\' => 13,
|
||||
),
|
||||
'F' =>
|
||||
array (
|
||||
'FG\\' => 3,
|
||||
),
|
||||
'C' =>
|
||||
array (
|
||||
'Cose\\' => 5,
|
||||
'CBOR\\' => 5,
|
||||
),
|
||||
'B' =>
|
||||
array (
|
||||
'Base64Url\\' => 10,
|
||||
),
|
||||
'A' =>
|
||||
array (
|
||||
'Assert\\' => 7,
|
||||
),
|
||||
);
|
||||
|
||||
public static $prefixDirsPsr4 = array (
|
||||
'Webauthn\\MetadataService\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/web-auth/metadata-service/src',
|
||||
),
|
||||
'Webauthn\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/web-auth/webauthn-lib/src',
|
||||
),
|
||||
'Symfony\\Polyfill\\Php72\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/symfony/polyfill-php72',
|
||||
),
|
||||
'Symfony\\Polyfill\\Mbstring\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring',
|
||||
),
|
||||
'Symfony\\Polyfill\\Intl\\Idn\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/symfony/polyfill-intl-idn',
|
||||
),
|
||||
'Symfony\\Polyfill\\Ctype\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/symfony/polyfill-ctype',
|
||||
),
|
||||
'Symfony\\Component\\Mime\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/symfony/mime',
|
||||
),
|
||||
'Symfony\\Component\\HttpFoundation\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/symfony/http-foundation',
|
||||
),
|
||||
'Symfony\\Bridge\\PsrHttpMessage\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/symfony/psr-http-message-bridge',
|
||||
),
|
||||
'Ramsey\\Uuid\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/ramsey/uuid/src',
|
||||
),
|
||||
'Psr\\Http\\Message\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/psr/http-factory/src',
|
||||
1 => __DIR__ . '/..' . '/psr/http-message/src',
|
||||
),
|
||||
'Psr\\Http\\Client\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/psr/http-client/src',
|
||||
),
|
||||
'Nyholm\\Psr7\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/nyholm/psr7/src',
|
||||
),
|
||||
'Http\\Message\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/php-http/message-factory/src',
|
||||
),
|
||||
'FG\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/fgrosse/phpasn1/lib',
|
||||
),
|
||||
'Cose\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/web-auth/cose-lib/src',
|
||||
),
|
||||
'CBOR\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/spomky-labs/cbor-php/src',
|
||||
),
|
||||
'Base64Url\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/spomky-labs/base64url/src',
|
||||
),
|
||||
'Assert\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/beberlei/assert/lib/Assert',
|
||||
),
|
||||
);
|
||||
|
||||
public static function getInitializer(ClassLoader $loader)
|
||||
{
|
||||
return \Closure::bind(function () use ($loader) {
|
||||
$loader->prefixLengthsPsr4 = ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5::$prefixLengthsPsr4;
|
||||
$loader->prefixDirsPsr4 = ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5::$prefixDirsPsr4;
|
||||
|
||||
}, null, ClassLoader::class);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,38 @@
|
|||
#### v.2.1.0 (2018-03)
|
||||
* add support for `bcmath` extension (making `gmp` optional)<br>
|
||||
https://github.com/fgrosse/PHPASN1/pull/68
|
||||
|
||||
#### v.2.0.1 & v.1.5.3 (2017-12)
|
||||
* add .gitattributes file to prevent examples and tests to be installed via composer when --prefer-dist was set
|
||||
|
||||
#### v.2.0.0 (2017-08)
|
||||
* rename `FG\ASN1\Object` to `FG\ASN1\ASNObject` because `Object` is a special class name in the next major PHP release
|
||||
- when you upgrade you have to adapt all corresponding `use` and `extends` statements as well as type hints and all
|
||||
usages of `Object::fromBinary(…)`.
|
||||
* generally drop PHP 5.6 support
|
||||
|
||||
#### v.1.5.2 (2016-10-29)
|
||||
* allow empty octet strings
|
||||
|
||||
#### v.1.5.1 (2015-10-02)
|
||||
* add keywords to composer.json (this is a version on its own so the keywords are found on a stable version at packagist.org)
|
||||
|
||||
#### v.1.5.0 (2015-10-30)
|
||||
* fix a bug that would prevent you from decoding context specific tags on multiple objects [#57](https://github.com/fgrosse/PHPASN1/issues/57)
|
||||
- `ExplicitlyTaggedObject::__construct` does now accept multiple objects to be tagged with a single tag
|
||||
- `ExplicitlyTaggedObject::getContent` will now always return an array (even if only one object is tagged)
|
||||
|
||||
#### v.1.4.2 (2015-09-29)
|
||||
* fix a bug that would prevent you from decoding empty tagged objects [#57](https://github.com/fgrosse/PHPASN1/issues/57)
|
||||
|
||||
#### v.1.4.1
|
||||
* improve exception messages and general error handling [#55](https://github.com/fgrosse/PHPASN1/pull/55)
|
||||
|
||||
#### v.1.4.0
|
||||
* **require PHP 5.6**
|
||||
* support big integers (closes #1 and #37)
|
||||
* enforce one code style via [styleci.io][9]
|
||||
* track code coverage via [coveralls.io][10]
|
||||
* replace obsolete `FG\ASN1\Exception\GeneralException` with `\Exception`
|
||||
* `Construct` (`Sequence`, `Set`) does now implement `ArrayAccess`, `Countable` and `Iterator` so its easier to use
|
||||
* add [`TemplateParser`][11]
|
|
@ -0,0 +1,19 @@
|
|||
Copyright (c) 2012-2015 Friedrich Große <friedrich.grosse@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1,167 @@
|
|||
PHPASN1
|
||||
=======
|
||||
|
||||
[![Build Status](https://secure.travis-ci.org/fgrosse/PHPASN1.png?branch=master)](http://travis-ci.org/fgrosse/PHPASN1)
|
||||
[![PHP 7 ready](http://php7ready.timesplinter.ch/fgrosse/PHPASN1/badge.svg)](https://travis-ci.org/fgrosse/PHPASN1)
|
||||
[![Coverage Status](https://coveralls.io/repos/fgrosse/PHPASN1/badge.svg?branch=master&service=github)](https://coveralls.io/github/fgrosse/PHPASN1?branch=master)
|
||||
|
||||
[![Latest Stable Version](https://poser.pugx.org/fgrosse/phpasn1/v/stable.png)](https://packagist.org/packages/fgrosse/phpasn1)
|
||||
[![Total Downloads](https://poser.pugx.org/fgrosse/phpasn1/downloads.png)](https://packagist.org/packages/fgrosse/phpasn1)
|
||||
[![Latest Unstable Version](https://poser.pugx.org/fgrosse/phpasn1/v/unstable.png)](https://packagist.org/packages/fgrosse/phpasn1)
|
||||
[![License](https://poser.pugx.org/fgrosse/phpasn1/license.png)](https://packagist.org/packages/fgrosse/phpasn1)
|
||||
|
||||
A PHP Framework that allows you to encode and decode arbitrary [ASN.1][3] structures
|
||||
using the [ITU-T X.690 Encoding Rules][4].
|
||||
This encoding is very frequently used in [X.509 PKI environments][5] or the communication between heterogeneous computer systems.
|
||||
|
||||
The API allows you to encode ASN.1 structures to create binary data such as certificate
|
||||
signing requests (CSR), X.509 certificates or certificate revocation lists (CRL).
|
||||
PHPASN1 can also read [BER encoded][6] binary data into separate PHP objects that can be manipulated by the user and reencoded afterwards.
|
||||
|
||||
The **changelog** can now be found at [CHANGELOG.md](CHANGELOG.md).
|
||||
|
||||
## Dependencies
|
||||
|
||||
PHPASN1 requires at least `PHP 7.0` and either the `gmp` or `bcmath` extension.
|
||||
Support for older PHP versions (i.e. PHP 5.6) was dropped starting with `v2.0`.
|
||||
If you must use an outdated PHP version consider using [PHPASN v1.5][13].
|
||||
|
||||
For the loading of object identifier names directly from the web [curl][7] is used.
|
||||
|
||||
## Installation
|
||||
|
||||
The preferred way to install this library is to rely on [Composer][2]:
|
||||
|
||||
```bash
|
||||
$ composer require fgrosse/phpasn1
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Encoding ASN.1 Structures
|
||||
|
||||
PHPASN1 offers you a class for each of the implemented ASN.1 universal types.
|
||||
The constructors should be pretty self explanatory so you should have no big trouble getting started.
|
||||
All data will be encoded using [DER encoding][8]
|
||||
|
||||
```php
|
||||
use FG\ASN1\OID;
|
||||
use FG\ASN1\Universal\Integer;
|
||||
use FG\ASN1\Universal\Boolean;
|
||||
use FG\ASN1\Universal\Enumerated;
|
||||
use FG\ASN1\Universal\IA5String;
|
||||
use FG\ASN1\Universal\ObjectIdentifier;
|
||||
use FG\ASN1\Universal\PrintableString;
|
||||
use FG\ASN1\Universal\Sequence;
|
||||
use FG\ASN1\Universal\Set;
|
||||
use FG\ASN1\Universal\NullObject;
|
||||
|
||||
$integer = new Integer(123456);
|
||||
$boolean = new Boolean(true);
|
||||
$enum = new Enumerated(1);
|
||||
$ia5String = new IA5String('Hello world');
|
||||
|
||||
$asnNull = new NullObject();
|
||||
$objectIdentifier1 = new ObjectIdentifier('1.2.250.1.16.9');
|
||||
$objectIdentifier2 = new ObjectIdentifier(OID::RSA_ENCRYPTION);
|
||||
$printableString = new PrintableString('Foo bar');
|
||||
|
||||
$sequence = new Sequence($integer, $boolean, $enum, $ia5String);
|
||||
$set = new Set($sequence, $asnNull, $objectIdentifier1, $objectIdentifier2, $printableString);
|
||||
|
||||
$myBinary = $sequence->getBinary();
|
||||
$myBinary .= $set->getBinary();
|
||||
|
||||
echo base64_encode($myBinary);
|
||||
```
|
||||
|
||||
|
||||
### Decoding binary data
|
||||
|
||||
Decoding BER encoded binary data is just as easy as encoding it:
|
||||
|
||||
```php
|
||||
use FG\ASN1\ASNObject;
|
||||
|
||||
$base64String = ...
|
||||
$binaryData = base64_decode($base64String);
|
||||
$asnObject = ASNObject::fromBinary($binaryData);
|
||||
|
||||
|
||||
// do stuff
|
||||
```
|
||||
|
||||
If you already know exactly how your expected data should look like you can use the `FG\ASN1\TemplateParser`:
|
||||
|
||||
```php
|
||||
use FG\ASN1\TemplateParser;
|
||||
|
||||
// first define your template
|
||||
$template = [
|
||||
Identifier::SEQUENCE => [
|
||||
Identifier::SET => [
|
||||
Identifier::OBJECT_IDENTIFIER,
|
||||
Identifier::SEQUENCE => [
|
||||
Identifier::INTEGER,
|
||||
Identifier::BITSTRING,
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
// if your binary data is not matching the template you provided this will throw an `\Exception`:
|
||||
$parser = new TemplateParser();
|
||||
$object = $parser->parseBinary($data, $template);
|
||||
|
||||
// there is also a convenience function if you parse binary data from base64:
|
||||
$object = $parser->parseBase64($data, $template);
|
||||
```
|
||||
|
||||
You can use this function to make sure your data has exactly the format you are expecting.
|
||||
|
||||
### Navigating decoded data
|
||||
|
||||
All constructed classes (i.e. `Sequence` and `Set`) can be navigated by array access or using an iterator.
|
||||
You can find examples
|
||||
[here](https://github.com/fgrosse/PHPASN1/blob/f6442cadda9d36f3518c737e32f28300a588b777/tests/ASN1/Universal/SequenceTest.php#L148-148),
|
||||
[here](https://github.com/fgrosse/PHPASN1/blob/f6442cadda9d36f3518c737e32f28300a588b777/tests/ASN1/Universal/SequenceTest.php#L121) and
|
||||
[here](https://github.com/fgrosse/PHPASN1/blob/f6442cadda9d36f3518c737e32f28300a588b777/tests/ASN1/TemplateParserTest.php#L45).
|
||||
|
||||
|
||||
### Give me more examples!
|
||||
|
||||
To see some example usage of the API classes or some generated output check out the [examples](https://github.com/fgrosse/PHPASN1/tree/master/examples).
|
||||
|
||||
|
||||
### How do I contribute?
|
||||
|
||||
If you found an issue or have a question submit a github issue with detailed information.
|
||||
|
||||
In case you already know what caused the issue and feel in the mood to fix it, your code contributions are always welcome. Just fork the repository, implement your changes and make sure that you covered everything with tests.
|
||||
Afterwards submit a pull request via github and be a little patient :) I usually try to comment and/or merge as soon as possible.
|
||||
|
||||
#### Mailing list
|
||||
|
||||
New features or questions can be discussed in [this google group/mailing list][12].
|
||||
|
||||
### Thanks
|
||||
|
||||
To [all contributors][1] so far!
|
||||
|
||||
## License
|
||||
|
||||
This library is distributed under the [MIT License](LICENSE).
|
||||
|
||||
[1]: https://github.com/fgrosse/PHPASN1/graphs/contributors
|
||||
[2]: https://getcomposer.org/
|
||||
[3]: http://www.itu.int/ITU-T/asn1/
|
||||
[4]: http://www.itu.int/ITU-T/recommendations/rec.aspx?rec=x.690
|
||||
[5]: http://en.wikipedia.org/wiki/X.509
|
||||
[6]: http://en.wikipedia.org/wiki/X.690#BER_encoding
|
||||
[7]: http://php.net/manual/en/book.curl.php
|
||||
[8]: http://en.wikipedia.org/wiki/X.690#DER_encoding
|
||||
[9]: https://styleci.io
|
||||
[10]: https://coveralls.io/github/fgrosse/PHPASN1
|
||||
[11]: https://github.com/fgrosse/PHPASN1/blob/master/tests/ASN1/TemplateParserTest.php#L16
|
||||
[12]: https://groups.google.com/d/forum/phpasn1
|
||||
[13]: https://packagist.org/packages/fgrosse/phpasn1#1.5.2
|
|
@ -0,0 +1,47 @@
|
|||
{
|
||||
"name": "fgrosse/phpasn1",
|
||||
"description": "A PHP Framework that allows you to encode and decode arbitrary ASN.1 structures using the ITU-T X.690 Encoding Rules.",
|
||||
"type": "library",
|
||||
"homepage": "https://github.com/FGrosse/PHPASN1",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Friedrich Große",
|
||||
"email": "friedrich.grosse@gmail.com",
|
||||
"homepage": "https://github.com/FGrosse",
|
||||
"role": "Author"
|
||||
},
|
||||
{
|
||||
"name": "All contributors",
|
||||
"homepage": "https://github.com/FGrosse/PHPASN1/contributors"
|
||||
}
|
||||
],
|
||||
"keywords": [ "x690", "x.690", "x.509", "x509", "asn1", "asn.1", "ber", "der", "binary", "encoding", "decoding" ],
|
||||
|
||||
"require": {
|
||||
"php": ">=7.0.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~6.3",
|
||||
"satooshi/php-coveralls": "~2.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-gmp": "GMP is the preferred extension for big integer calculations",
|
||||
"php-curl": "For loading OID information from the web if they have not bee defined statically"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"FG\\": "lib/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"FG\\Test\\": "tests/"
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.0.x-dev"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,355 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\ASN1;
|
||||
|
||||
use FG\ASN1\Exception\ParserException;
|
||||
use FG\ASN1\Universal\BitString;
|
||||
use FG\ASN1\Universal\Boolean;
|
||||
use FG\ASN1\Universal\Enumerated;
|
||||
use FG\ASN1\Universal\GeneralizedTime;
|
||||
use FG\ASN1\Universal\Integer;
|
||||
use FG\ASN1\Universal\NullObject;
|
||||
use FG\ASN1\Universal\ObjectIdentifier;
|
||||
use FG\ASN1\Universal\RelativeObjectIdentifier;
|
||||
use FG\ASN1\Universal\OctetString;
|
||||
use FG\ASN1\Universal\Sequence;
|
||||
use FG\ASN1\Universal\Set;
|
||||
use FG\ASN1\Universal\UTCTime;
|
||||
use FG\ASN1\Universal\IA5String;
|
||||
use FG\ASN1\Universal\PrintableString;
|
||||
use FG\ASN1\Universal\NumericString;
|
||||
use FG\ASN1\Universal\UTF8String;
|
||||
use FG\ASN1\Universal\UniversalString;
|
||||
use FG\ASN1\Universal\CharacterString;
|
||||
use FG\ASN1\Universal\GeneralString;
|
||||
use FG\ASN1\Universal\VisibleString;
|
||||
use FG\ASN1\Universal\GraphicString;
|
||||
use FG\ASN1\Universal\BMPString;
|
||||
use FG\ASN1\Universal\T61String;
|
||||
use FG\ASN1\Universal\ObjectDescriptor;
|
||||
use FG\Utility\BigInteger;
|
||||
use LogicException;
|
||||
|
||||
/**
|
||||
* Class ASNObject is the base class for all concrete ASN.1 objects.
|
||||
*/
|
||||
abstract class ASNObject implements Parsable
|
||||
{
|
||||
private $contentLength;
|
||||
private $nrOfLengthOctets;
|
||||
|
||||
/**
|
||||
* Must return the number of octets of the content part.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
abstract protected function calculateContentLength();
|
||||
|
||||
/**
|
||||
* Encode the object using DER encoding.
|
||||
*
|
||||
* @see http://en.wikipedia.org/wiki/X.690#DER_encoding
|
||||
*
|
||||
* @return string the binary representation of an objects value
|
||||
*/
|
||||
abstract protected function getEncodedValue();
|
||||
|
||||
/**
|
||||
* Return the content of this object in a non encoded form.
|
||||
* This can be used to print the value in human readable form.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function getContent();
|
||||
|
||||
/**
|
||||
* Return the object type octet.
|
||||
* This should use the class constants of Identifier.
|
||||
*
|
||||
* @see Identifier
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
abstract public function getType();
|
||||
|
||||
/**
|
||||
* Returns all identifier octets. If an inheriting class models a tag with
|
||||
* the long form identifier format, it MUST reimplement this method to
|
||||
* return all octets of the identifier.
|
||||
*
|
||||
* @throws LogicException If the identifier format is long form
|
||||
*
|
||||
* @return string Identifier as a set of octets
|
||||
*/
|
||||
public function getIdentifier()
|
||||
{
|
||||
$firstOctet = $this->getType();
|
||||
|
||||
if (Identifier::isLongForm($firstOctet)) {
|
||||
throw new LogicException(sprintf('Identifier of %s uses the long form and must therefor override "ASNObject::getIdentifier()".', get_class($this)));
|
||||
}
|
||||
|
||||
return chr($firstOctet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode this object using DER encoding.
|
||||
*
|
||||
* @return string the full binary representation of the complete object
|
||||
*/
|
||||
public function getBinary()
|
||||
{
|
||||
$result = $this->getIdentifier();
|
||||
$result .= $this->createLengthPart();
|
||||
$result .= $this->getEncodedValue();
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function createLengthPart()
|
||||
{
|
||||
$contentLength = $this->getContentLength();
|
||||
$nrOfLengthOctets = $this->getNumberOfLengthOctets($contentLength);
|
||||
|
||||
if ($nrOfLengthOctets == 1) {
|
||||
return chr($contentLength);
|
||||
} else {
|
||||
// the first length octet determines the number subsequent length octets
|
||||
$lengthOctets = chr(0x80 | ($nrOfLengthOctets - 1));
|
||||
for ($shiftLength = 8 * ($nrOfLengthOctets - 2); $shiftLength >= 0; $shiftLength -= 8) {
|
||||
$lengthOctets .= chr($contentLength >> $shiftLength);
|
||||
}
|
||||
|
||||
return $lengthOctets;
|
||||
}
|
||||
}
|
||||
|
||||
protected function getNumberOfLengthOctets($contentLength = null)
|
||||
{
|
||||
if (!isset($this->nrOfLengthOctets)) {
|
||||
if ($contentLength == null) {
|
||||
$contentLength = $this->getContentLength();
|
||||
}
|
||||
|
||||
$this->nrOfLengthOctets = 1;
|
||||
if ($contentLength > 127) {
|
||||
do { // long form
|
||||
$this->nrOfLengthOctets++;
|
||||
$contentLength = $contentLength >> 8;
|
||||
} while ($contentLength > 0);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->nrOfLengthOctets;
|
||||
}
|
||||
|
||||
protected function getContentLength()
|
||||
{
|
||||
if (!isset($this->contentLength)) {
|
||||
$this->contentLength = $this->calculateContentLength();
|
||||
}
|
||||
|
||||
return $this->contentLength;
|
||||
}
|
||||
|
||||
protected function setContentLength($newContentLength)
|
||||
{
|
||||
$this->contentLength = $newContentLength;
|
||||
$this->getNumberOfLengthOctets($newContentLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of the whole object (including the identifier and length octets).
|
||||
*/
|
||||
public function getObjectLength()
|
||||
{
|
||||
$nrOfIdentifierOctets = strlen($this->getIdentifier());
|
||||
$contentLength = $this->getContentLength();
|
||||
$nrOfLengthOctets = $this->getNumberOfLengthOctets($contentLength);
|
||||
|
||||
return $nrOfIdentifierOctets + $nrOfLengthOctets + $contentLength;
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return $this->getContent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the ASN.1 Type of this object.
|
||||
*
|
||||
* @see Identifier::getName()
|
||||
*/
|
||||
public function getTypeName()
|
||||
{
|
||||
return Identifier::getName($this->getType());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $binaryData
|
||||
* @param int $offsetIndex
|
||||
*
|
||||
* @throws ParserException
|
||||
*
|
||||
* @return \FG\ASN1\ASNObject
|
||||
*/
|
||||
public static function fromBinary(&$binaryData, &$offsetIndex = 0)
|
||||
{
|
||||
if (strlen($binaryData) <= $offsetIndex) {
|
||||
throw new ParserException('Can not parse binary from data: Offset index larger than input size', $offsetIndex);
|
||||
}
|
||||
|
||||
$identifierOctet = ord($binaryData[$offsetIndex]);
|
||||
if (Identifier::isContextSpecificClass($identifierOctet) && Identifier::isConstructed($identifierOctet)) {
|
||||
return ExplicitlyTaggedObject::fromBinary($binaryData, $offsetIndex);
|
||||
}
|
||||
|
||||
switch ($identifierOctet) {
|
||||
case Identifier::BITSTRING:
|
||||
return BitString::fromBinary($binaryData, $offsetIndex);
|
||||
case Identifier::BOOLEAN:
|
||||
return Boolean::fromBinary($binaryData, $offsetIndex);
|
||||
case Identifier::ENUMERATED:
|
||||
return Enumerated::fromBinary($binaryData, $offsetIndex);
|
||||
case Identifier::INTEGER:
|
||||
return Integer::fromBinary($binaryData, $offsetIndex);
|
||||
case Identifier::NULL:
|
||||
return NullObject::fromBinary($binaryData, $offsetIndex);
|
||||
case Identifier::OBJECT_IDENTIFIER:
|
||||
return ObjectIdentifier::fromBinary($binaryData, $offsetIndex);
|
||||
case Identifier::RELATIVE_OID:
|
||||
return RelativeObjectIdentifier::fromBinary($binaryData, $offsetIndex);
|
||||
case Identifier::OCTETSTRING:
|
||||
return OctetString::fromBinary($binaryData, $offsetIndex);
|
||||
case Identifier::SEQUENCE:
|
||||
return Sequence::fromBinary($binaryData, $offsetIndex);
|
||||
case Identifier::SET:
|
||||
return Set::fromBinary($binaryData, $offsetIndex);
|
||||
case Identifier::UTC_TIME:
|
||||
return UTCTime::fromBinary($binaryData, $offsetIndex);
|
||||
case Identifier::GENERALIZED_TIME:
|
||||
return GeneralizedTime::fromBinary($binaryData, $offsetIndex);
|
||||
case Identifier::IA5_STRING:
|
||||
return IA5String::fromBinary($binaryData, $offsetIndex);
|
||||
case Identifier::PRINTABLE_STRING:
|
||||
return PrintableString::fromBinary($binaryData, $offsetIndex);
|
||||
case Identifier::NUMERIC_STRING:
|
||||
return NumericString::fromBinary($binaryData, $offsetIndex);
|
||||
case Identifier::UTF8_STRING:
|
||||
return UTF8String::fromBinary($binaryData, $offsetIndex);
|
||||
case Identifier::UNIVERSAL_STRING:
|
||||
return UniversalString::fromBinary($binaryData, $offsetIndex);
|
||||
case Identifier::CHARACTER_STRING:
|
||||
return CharacterString::fromBinary($binaryData, $offsetIndex);
|
||||
case Identifier::GENERAL_STRING:
|
||||
return GeneralString::fromBinary($binaryData, $offsetIndex);
|
||||
case Identifier::VISIBLE_STRING:
|
||||
return VisibleString::fromBinary($binaryData, $offsetIndex);
|
||||
case Identifier::GRAPHIC_STRING:
|
||||
return GraphicString::fromBinary($binaryData, $offsetIndex);
|
||||
case Identifier::BMP_STRING:
|
||||
return BMPString::fromBinary($binaryData, $offsetIndex);
|
||||
case Identifier::T61_STRING:
|
||||
return T61String::fromBinary($binaryData, $offsetIndex);
|
||||
case Identifier::OBJECT_DESCRIPTOR:
|
||||
return ObjectDescriptor::fromBinary($binaryData, $offsetIndex);
|
||||
default:
|
||||
// At this point the identifier may be >1 byte.
|
||||
if (Identifier::isConstructed($identifierOctet)) {
|
||||
return new UnknownConstructedObject($binaryData, $offsetIndex);
|
||||
} else {
|
||||
$identifier = self::parseBinaryIdentifier($binaryData, $offsetIndex);
|
||||
$lengthOfUnknownObject = self::parseContentLength($binaryData, $offsetIndex);
|
||||
$offsetIndex += $lengthOfUnknownObject;
|
||||
|
||||
return new UnknownObject($identifier, $lengthOfUnknownObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected static function parseIdentifier($identifierOctet, $expectedIdentifier, $offsetForExceptionHandling)
|
||||
{
|
||||
if (is_string($identifierOctet) || is_numeric($identifierOctet) == false) {
|
||||
$identifierOctet = ord($identifierOctet);
|
||||
}
|
||||
|
||||
if ($identifierOctet != $expectedIdentifier) {
|
||||
$message = 'Can not create an '.Identifier::getName($expectedIdentifier).' from an '.Identifier::getName($identifierOctet);
|
||||
throw new ParserException($message, $offsetForExceptionHandling);
|
||||
}
|
||||
}
|
||||
|
||||
protected static function parseBinaryIdentifier($binaryData, &$offsetIndex)
|
||||
{
|
||||
if (strlen($binaryData) <= $offsetIndex) {
|
||||
throw new ParserException('Can not parse identifier from data: Offset index larger than input size', $offsetIndex);
|
||||
}
|
||||
|
||||
$identifier = $binaryData[$offsetIndex++];
|
||||
|
||||
if (Identifier::isLongForm(ord($identifier)) == false) {
|
||||
return $identifier;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
if (strlen($binaryData) <= $offsetIndex) {
|
||||
throw new ParserException('Can not parse identifier (long form) from data: Offset index larger than input size', $offsetIndex);
|
||||
}
|
||||
$nextOctet = $binaryData[$offsetIndex++];
|
||||
$identifier .= $nextOctet;
|
||||
|
||||
if ((ord($nextOctet) & 0x80) === 0) {
|
||||
// the most significant bit is 0 to we have reached the end of the identifier
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $identifier;
|
||||
}
|
||||
|
||||
protected static function parseContentLength(&$binaryData, &$offsetIndex, $minimumLength = 0)
|
||||
{
|
||||
if (strlen($binaryData) <= $offsetIndex) {
|
||||
throw new ParserException('Can not parse content length from data: Offset index larger than input size', $offsetIndex);
|
||||
}
|
||||
|
||||
$contentLength = ord($binaryData[$offsetIndex++]);
|
||||
if (($contentLength & 0x80) != 0) {
|
||||
// bit 8 is set -> this is the long form
|
||||
$nrOfLengthOctets = $contentLength & 0x7F;
|
||||
$contentLength = BigInteger::create(0x00);
|
||||
for ($i = 0; $i < $nrOfLengthOctets; $i++) {
|
||||
if (strlen($binaryData) <= $offsetIndex) {
|
||||
throw new ParserException('Can not parse content length (long form) from data: Offset index larger than input size', $offsetIndex);
|
||||
}
|
||||
$contentLength = $contentLength->shiftLeft(8)->add(ord($binaryData[$offsetIndex++]));
|
||||
}
|
||||
|
||||
if ($contentLength->compare(PHP_INT_MAX) > 0) {
|
||||
throw new ParserException("Can not parse content length from data: length > maximum integer", $offsetIndex);
|
||||
}
|
||||
|
||||
$contentLength = $contentLength->toInteger();
|
||||
}
|
||||
|
||||
if ($contentLength < $minimumLength) {
|
||||
throw new ParserException('A '.get_called_class()." should have a content length of at least {$minimumLength}. Extracted length was {$contentLength}", $offsetIndex);
|
||||
}
|
||||
|
||||
$lenDataRemaining = strlen($binaryData) - $offsetIndex;
|
||||
|
||||
if ($lenDataRemaining < $contentLength) {
|
||||
throw new ParserException("Content length {$contentLength} exceeds remaining data length {$lenDataRemaining}", $offsetIndex);
|
||||
}
|
||||
|
||||
return $contentLength;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\ASN1;
|
||||
|
||||
use Exception;
|
||||
|
||||
abstract class AbstractString extends ASNObject implements Parsable
|
||||
{
|
||||
/** @var string */
|
||||
protected $value;
|
||||
private $checkStringForIllegalChars = true;
|
||||
private $allowedCharacters = [];
|
||||
|
||||
/**
|
||||
* The abstract base class for ASN.1 classes which represent some string of character.
|
||||
*
|
||||
* @param string $string
|
||||
*/
|
||||
public function __construct($string)
|
||||
{
|
||||
$this->value = $string;
|
||||
}
|
||||
|
||||
public function getContent()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
protected function allowCharacter($character)
|
||||
{
|
||||
$this->allowedCharacters[] = $character;
|
||||
}
|
||||
|
||||
protected function allowCharacters(...$characters)
|
||||
{
|
||||
foreach ($characters as $character) {
|
||||
$this->allowedCharacters[] = $character;
|
||||
}
|
||||
}
|
||||
|
||||
protected function allowNumbers()
|
||||
{
|
||||
foreach (range('0', '9') as $char) {
|
||||
$this->allowedCharacters[] = (string) $char;
|
||||
}
|
||||
}
|
||||
|
||||
protected function allowAllLetters()
|
||||
{
|
||||
$this->allowSmallLetters();
|
||||
$this->allowCapitalLetters();
|
||||
}
|
||||
|
||||
protected function allowSmallLetters()
|
||||
{
|
||||
foreach (range('a', 'z') as $char) {
|
||||
$this->allowedCharacters[] = $char;
|
||||
}
|
||||
}
|
||||
|
||||
protected function allowCapitalLetters()
|
||||
{
|
||||
foreach (range('A', 'Z') as $char) {
|
||||
$this->allowedCharacters[] = $char;
|
||||
}
|
||||
}
|
||||
|
||||
protected function allowSpaces()
|
||||
{
|
||||
$this->allowedCharacters[] = ' ';
|
||||
}
|
||||
|
||||
protected function allowAll()
|
||||
{
|
||||
$this->checkStringForIllegalChars = false;
|
||||
}
|
||||
|
||||
protected function calculateContentLength()
|
||||
{
|
||||
return strlen($this->value);
|
||||
}
|
||||
|
||||
protected function getEncodedValue()
|
||||
{
|
||||
if ($this->checkStringForIllegalChars) {
|
||||
$this->checkString();
|
||||
}
|
||||
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
protected function checkString()
|
||||
{
|
||||
$stringLength = $this->getContentLength();
|
||||
for ($i = 0; $i < $stringLength; $i++) {
|
||||
if (in_array($this->value[$i], $this->allowedCharacters) == false) {
|
||||
$typeName = Identifier::getName($this->getType());
|
||||
throw new Exception("Could not create a {$typeName} from the character sequence '{$this->value}'.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function fromBinary(&$binaryData, &$offsetIndex = 0)
|
||||
{
|
||||
$parsedObject = new static('');
|
||||
|
||||
self::parseIdentifier($binaryData[$offsetIndex], $parsedObject->getType(), $offsetIndex++);
|
||||
$contentLength = self::parseContentLength($binaryData, $offsetIndex);
|
||||
$string = substr($binaryData, $offsetIndex, $contentLength);
|
||||
$offsetIndex += $contentLength;
|
||||
|
||||
$parsedObject->value = $string;
|
||||
$parsedObject->setContentLength($contentLength);
|
||||
return $parsedObject;
|
||||
}
|
||||
|
||||
public static function isValid($string)
|
||||
{
|
||||
$testObject = new static($string);
|
||||
try {
|
||||
$testObject->checkString();
|
||||
|
||||
return true;
|
||||
} catch (Exception $exception) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\ASN1;
|
||||
|
||||
use DateInterval;
|
||||
use DateTime;
|
||||
use DateTimeZone;
|
||||
use Exception;
|
||||
|
||||
abstract class AbstractTime extends ASNObject
|
||||
{
|
||||
/** @var DateTime */
|
||||
protected $value;
|
||||
|
||||
public function __construct($dateTime = null, $dateTimeZone = 'UTC')
|
||||
{
|
||||
if ($dateTime == null || is_string($dateTime)) {
|
||||
$timeZone = new DateTimeZone($dateTimeZone);
|
||||
$dateTimeObject = new DateTime($dateTime, $timeZone);
|
||||
if ($dateTimeObject == false) {
|
||||
$errorMessage = $this->getLastDateTimeErrors();
|
||||
$className = Identifier::getName($this->getType());
|
||||
throw new Exception(sprintf("Could not create %s from date time string '%s': %s", $className, $dateTime, $errorMessage));
|
||||
}
|
||||
$dateTime = $dateTimeObject;
|
||||
} elseif (!$dateTime instanceof DateTime) {
|
||||
throw new Exception('Invalid first argument for some instance of AbstractTime constructor');
|
||||
}
|
||||
|
||||
$this->value = $dateTime;
|
||||
}
|
||||
|
||||
public function getContent()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
protected function getLastDateTimeErrors()
|
||||
{
|
||||
$messages = '';
|
||||
$lastErrors = DateTime::getLastErrors();
|
||||
foreach ($lastErrors['errors'] as $errorMessage) {
|
||||
$messages .= "{$errorMessage}, ";
|
||||
}
|
||||
|
||||
return substr($messages, 0, -2);
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return $this->value->format("Y-m-d\tH:i:s");
|
||||
}
|
||||
|
||||
protected static function extractTimeZoneData(&$binaryData, &$offsetIndex, DateTime $dateTime)
|
||||
{
|
||||
$sign = $binaryData[$offsetIndex++];
|
||||
$timeOffsetHours = intval(substr($binaryData, $offsetIndex, 2));
|
||||
$timeOffsetMinutes = intval(substr($binaryData, $offsetIndex + 2, 2));
|
||||
$offsetIndex += 4;
|
||||
|
||||
$interval = new DateInterval("PT{$timeOffsetHours}H{$timeOffsetMinutes}M");
|
||||
if ($sign == '+') {
|
||||
$dateTime->sub($interval);
|
||||
} else {
|
||||
$dateTime->add($interval);
|
||||
}
|
||||
|
||||
return $dateTime;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
|
||||
namespace FG\ASN1;
|
||||
|
||||
use FG\Utility\BigInteger;
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* A base-128 decoder.
|
||||
*/
|
||||
class Base128
|
||||
{
|
||||
/**
|
||||
* @param int $value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function encode($value)
|
||||
{
|
||||
$value = BigInteger::create($value);
|
||||
$octets = chr($value->modulus(0x80)->toInteger());
|
||||
|
||||
$value = $value->shiftRight(7);
|
||||
while ($value->compare(0) > 0) {
|
||||
$octets .= chr(0x80 | $value->modulus(0x80)->toInteger());
|
||||
$value = $value->shiftRight(7);
|
||||
}
|
||||
|
||||
return strrev($octets);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $octets
|
||||
*
|
||||
* @throws InvalidArgumentException if the given octets represent a malformed base-128 value or the decoded value would exceed the the maximum integer length
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function decode($octets)
|
||||
{
|
||||
$bitsPerOctet = 7;
|
||||
$value = BigInteger::create(0);
|
||||
$i = 0;
|
||||
|
||||
while (true) {
|
||||
if (!isset($octets[$i])) {
|
||||
throw new InvalidArgumentException(sprintf('Malformed base-128 encoded value (0x%s).', strtoupper(bin2hex($octets)) ?: '0'));
|
||||
}
|
||||
|
||||
$octet = ord($octets[$i++]);
|
||||
|
||||
$l1 = $value->shiftLeft($bitsPerOctet);
|
||||
$r1 = $octet & 0x7f;
|
||||
$value = $l1->add($r1);
|
||||
|
||||
if (0 === ($octet & 0x80)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (string)$value;
|
||||
}
|
||||
}
|
35
lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Composite/AttributeTypeAndValue.php
vendored
Normal file
35
lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Composite/AttributeTypeAndValue.php
vendored
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\ASN1\Composite;
|
||||
|
||||
use FG\ASN1\ASNObject;
|
||||
use FG\ASN1\Universal\Sequence;
|
||||
use FG\ASN1\Universal\ObjectIdentifier;
|
||||
|
||||
class AttributeTypeAndValue extends Sequence
|
||||
{
|
||||
/**
|
||||
* @param ObjectIdentifier|string $objIdentifier
|
||||
* @param \FG\ASN1\ASNObject $value
|
||||
*/
|
||||
public function __construct($objIdentifier, ASNObject $value)
|
||||
{
|
||||
if ($objIdentifier instanceof ObjectIdentifier == false) {
|
||||
$objIdentifier = new ObjectIdentifier($objIdentifier);
|
||||
}
|
||||
parent::__construct($objIdentifier, $value);
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return $this->children[0].': '.$this->children[1];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\ASN1\Composite;
|
||||
|
||||
use FG\ASN1\Universal\PrintableString;
|
||||
use FG\ASN1\Universal\IA5String;
|
||||
use FG\ASN1\Universal\UTF8String;
|
||||
|
||||
class RDNString extends RelativeDistinguishedName
|
||||
{
|
||||
/**
|
||||
* @param string|\FG\ASN1\Universal\ObjectIdentifier $objectIdentifierString
|
||||
* @param string|\FG\ASN1\ASNObject $value
|
||||
*/
|
||||
public function __construct($objectIdentifierString, $value)
|
||||
{
|
||||
if (PrintableString::isValid($value)) {
|
||||
$value = new PrintableString($value);
|
||||
} else {
|
||||
if (IA5String::isValid($value)) {
|
||||
$value = new IA5String($value);
|
||||
} else {
|
||||
$value = new UTF8String($value);
|
||||
}
|
||||
}
|
||||
|
||||
parent::__construct($objectIdentifierString, $value);
|
||||
}
|
||||
}
|
50
lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Composite/RelativeDistinguishedName.php
vendored
Normal file
50
lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Composite/RelativeDistinguishedName.php
vendored
Normal file
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\ASN1\Composite;
|
||||
|
||||
use FG\ASN1\Exception\NotImplementedException;
|
||||
use FG\ASN1\ASNObject;
|
||||
use FG\ASN1\Universal\Set;
|
||||
|
||||
class RelativeDistinguishedName extends Set
|
||||
{
|
||||
/**
|
||||
* @param string|\FG\ASN1\Universal\ObjectIdentifier $objIdentifierString
|
||||
* @param \FG\ASN1\ASNObject $value
|
||||
*/
|
||||
public function __construct($objIdentifierString, ASNObject $value)
|
||||
{
|
||||
// TODO: This does only support one element in the RelativeDistinguishedName Set but it it is defined as follows:
|
||||
// RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue
|
||||
parent::__construct(new AttributeTypeAndValue($objIdentifierString, $value));
|
||||
}
|
||||
|
||||
public function getContent()
|
||||
{
|
||||
/** @var \FG\ASN1\ASNObject $firstObject */
|
||||
$firstObject = $this->children[0];
|
||||
return $firstObject->__toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* At the current version this code can not work since the implementation of Construct requires
|
||||
* the class to support a constructor without arguments.
|
||||
*
|
||||
* @deprecated this function is not yet implemented! Feel free to submit a pull request on github
|
||||
* @param string $binaryData
|
||||
* @param int $offsetIndex
|
||||
* @throws NotImplementedException
|
||||
*/
|
||||
public static function fromBinary(&$binaryData, &$offsetIndex = 0)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,191 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\ASN1;
|
||||
|
||||
use ArrayAccess;
|
||||
use ArrayIterator;
|
||||
use Countable;
|
||||
use FG\ASN1\Exception\ParserException;
|
||||
use Iterator;
|
||||
|
||||
abstract class Construct extends ASNObject implements Countable, ArrayAccess, Iterator, Parsable
|
||||
{
|
||||
/** @var \FG\ASN1\ASNObject[] */
|
||||
protected $children;
|
||||
private $iteratorPosition;
|
||||
|
||||
/**
|
||||
* @param \FG\ASN1\ASNObject[] $children the variadic type hint is commented due to https://github.com/facebook/hhvm/issues/4858
|
||||
*/
|
||||
public function __construct(/* HH_FIXME[4858]: variadic + strict */ ...$children)
|
||||
{
|
||||
$this->children = $children;
|
||||
$this->iteratorPosition = 0;
|
||||
}
|
||||
|
||||
public function getContent()
|
||||
{
|
||||
return $this->children;
|
||||
}
|
||||
|
||||
public function rewind()
|
||||
{
|
||||
$this->iteratorPosition = 0;
|
||||
}
|
||||
|
||||
public function current()
|
||||
{
|
||||
return $this->children[$this->iteratorPosition];
|
||||
}
|
||||
|
||||
public function key()
|
||||
{
|
||||
return $this->iteratorPosition;
|
||||
}
|
||||
|
||||
public function next()
|
||||
{
|
||||
$this->iteratorPosition++;
|
||||
}
|
||||
|
||||
public function valid()
|
||||
{
|
||||
return isset($this->children[$this->iteratorPosition]);
|
||||
}
|
||||
|
||||
public function offsetExists($offset)
|
||||
{
|
||||
return array_key_exists($offset, $this->children);
|
||||
}
|
||||
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
return $this->children[$offset];
|
||||
}
|
||||
|
||||
public function offsetSet($offset, $value)
|
||||
{
|
||||
if ($offset === null) {
|
||||
$offset = count($this->children);
|
||||
}
|
||||
|
||||
$this->children[$offset] = $value;
|
||||
}
|
||||
|
||||
public function offsetUnset($offset)
|
||||
{
|
||||
unset($this->children[$offset]);
|
||||
}
|
||||
|
||||
protected function calculateContentLength()
|
||||
{
|
||||
$length = 0;
|
||||
foreach ($this->children as $component) {
|
||||
$length += $component->getObjectLength();
|
||||
}
|
||||
|
||||
return $length;
|
||||
}
|
||||
|
||||
protected function getEncodedValue()
|
||||
{
|
||||
$result = '';
|
||||
foreach ($this->children as $component) {
|
||||
$result .= $component->getBinary();
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function addChild(ASNObject $child)
|
||||
{
|
||||
$this->children[] = $child;
|
||||
}
|
||||
|
||||
public function addChildren(array $children)
|
||||
{
|
||||
foreach ($children as $child) {
|
||||
$this->addChild($child);
|
||||
}
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
$nrOfChildren = $this->getNumberOfChildren();
|
||||
$childString = $nrOfChildren == 1 ? 'child' : 'children';
|
||||
|
||||
return "[{$nrOfChildren} {$childString}]";
|
||||
}
|
||||
|
||||
public function getNumberOfChildren()
|
||||
{
|
||||
return count($this->children);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \FG\ASN1\ASNObject[]
|
||||
*/
|
||||
public function getChildren()
|
||||
{
|
||||
return $this->children;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \FG\ASN1\ASNObject
|
||||
*/
|
||||
public function getFirstChild()
|
||||
{
|
||||
return $this->children[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $binaryData
|
||||
* @param int $offsetIndex
|
||||
*
|
||||
* @throws Exception\ParserException
|
||||
*
|
||||
* @return Construct|static
|
||||
*/
|
||||
public static function fromBinary(&$binaryData, &$offsetIndex = 0)
|
||||
{
|
||||
$parsedObject = new static();
|
||||
self::parseIdentifier($binaryData[$offsetIndex], $parsedObject->getType(), $offsetIndex++);
|
||||
$contentLength = self::parseContentLength($binaryData, $offsetIndex);
|
||||
$startIndex = $offsetIndex;
|
||||
|
||||
$children = [];
|
||||
$octetsToRead = $contentLength;
|
||||
while ($octetsToRead > 0) {
|
||||
$newChild = ASNObject::fromBinary($binaryData, $offsetIndex);
|
||||
$octetsToRead -= $newChild->getObjectLength();
|
||||
$children[] = $newChild;
|
||||
}
|
||||
|
||||
if ($octetsToRead !== 0) {
|
||||
throw new ParserException("Sequence length incorrect", $startIndex);
|
||||
}
|
||||
|
||||
$parsedObject->addChildren($children);
|
||||
$parsedObject->setContentLength($contentLength);
|
||||
|
||||
return $parsedObject;
|
||||
}
|
||||
|
||||
public function count($mode = COUNT_NORMAL)
|
||||
{
|
||||
return count($this->children, $mode);
|
||||
}
|
||||
|
||||
public function getIterator()
|
||||
{
|
||||
return new ArrayIterator($this->children);
|
||||
}
|
||||
}
|
15
lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Exception/NotImplementedException.php
vendored
Normal file
15
lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Exception/NotImplementedException.php
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\ASN1\Exception;
|
||||
|
||||
class NotImplementedException extends \Exception
|
||||
{
|
||||
}
|
29
lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Exception/ParserException.php
vendored
Normal file
29
lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Exception/ParserException.php
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\ASN1\Exception;
|
||||
|
||||
class ParserException extends \Exception
|
||||
{
|
||||
private $errorMessage;
|
||||
private $offset;
|
||||
|
||||
public function __construct($errorMessage, $offset)
|
||||
{
|
||||
$this->errorMessage = $errorMessage;
|
||||
$this->offset = $offset;
|
||||
parent::__construct("ASN.1 Parser Exception at offset {$this->offset}: {$this->errorMessage}");
|
||||
}
|
||||
|
||||
public function getOffset()
|
||||
{
|
||||
return $this->offset;
|
||||
}
|
||||
}
|
131
lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/ExplicitlyTaggedObject.php
vendored
Normal file
131
lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/ExplicitlyTaggedObject.php
vendored
Normal file
|
@ -0,0 +1,131 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\ASN1;
|
||||
|
||||
use FG\ASN1\Exception\ParserException;
|
||||
|
||||
/**
|
||||
* Class ExplicitlyTaggedObject decorate an inner object with an additional tag that gives information about
|
||||
* its context specific meaning.
|
||||
*
|
||||
* Explanation taken from A Layman's Guide to a Subset of ASN.1, BER, and DER:
|
||||
* >>> An RSA Laboratories Technical Note
|
||||
* >>> Burton S. Kaliski Jr.
|
||||
* >>> Revised November 1, 1993
|
||||
*
|
||||
* [...]
|
||||
* Explicitly tagged types are derived from other types by adding an outer tag to the underlying type.
|
||||
* In effect, explicitly tagged types are structured types consisting of one component, the underlying type.
|
||||
* Explicit tagging is denoted by the ASN.1 keywords [class number] EXPLICIT (see Section 5.2).
|
||||
* [...]
|
||||
*
|
||||
* @see http://luca.ntop.org/Teaching/Appunti/asn1.html
|
||||
*/
|
||||
class ExplicitlyTaggedObject extends ASNObject
|
||||
{
|
||||
/** @var \FG\ASN1\ASNObject[] */
|
||||
private $decoratedObjects;
|
||||
private $tag;
|
||||
|
||||
/**
|
||||
* @param int $tag
|
||||
* @param \FG\ASN1\ASNObject $objects,...
|
||||
*/
|
||||
public function __construct($tag, /* HH_FIXME[4858]: variadic + strict */ ...$objects)
|
||||
{
|
||||
$this->tag = $tag;
|
||||
$this->decoratedObjects = $objects;
|
||||
}
|
||||
|
||||
protected function calculateContentLength()
|
||||
{
|
||||
$length = 0;
|
||||
foreach ($this->decoratedObjects as $object) {
|
||||
$length += $object->getObjectLength();
|
||||
}
|
||||
|
||||
return $length;
|
||||
}
|
||||
|
||||
protected function getEncodedValue()
|
||||
{
|
||||
$encoded = '';
|
||||
foreach ($this->decoratedObjects as $object) {
|
||||
$encoded .= $object->getBinary();
|
||||
}
|
||||
|
||||
return $encoded;
|
||||
}
|
||||
|
||||
public function getContent()
|
||||
{
|
||||
return $this->decoratedObjects;
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
switch ($length = count($this->decoratedObjects)) {
|
||||
case 0:
|
||||
return "Context specific empty object with tag [{$this->tag}]";
|
||||
case 1:
|
||||
$decoratedType = Identifier::getShortName($this->decoratedObjects[0]->getType());
|
||||
return "Context specific $decoratedType with tag [{$this->tag}]";
|
||||
default:
|
||||
return "$length context specific objects with tag [{$this->tag}]";
|
||||
}
|
||||
}
|
||||
|
||||
public function getType()
|
||||
{
|
||||
return ord($this->getIdentifier());
|
||||
}
|
||||
|
||||
public function getIdentifier()
|
||||
{
|
||||
$identifier = Identifier::create(Identifier::CLASS_CONTEXT_SPECIFIC, true, $this->tag);
|
||||
|
||||
return is_int($identifier) ? chr($identifier) : $identifier;
|
||||
}
|
||||
|
||||
public function getTag()
|
||||
{
|
||||
return $this->tag;
|
||||
}
|
||||
|
||||
public static function fromBinary(&$binaryData, &$offsetIndex = 0)
|
||||
{
|
||||
$identifier = self::parseBinaryIdentifier($binaryData, $offsetIndex);
|
||||
$firstIdentifierOctet = ord($identifier);
|
||||
assert(Identifier::isContextSpecificClass($firstIdentifierOctet), 'identifier octet should indicate context specific class');
|
||||
assert(Identifier::isConstructed($firstIdentifierOctet), 'identifier octet should indicate constructed object');
|
||||
$tag = Identifier::getTagNumber($identifier);
|
||||
|
||||
$totalContentLength = self::parseContentLength($binaryData, $offsetIndex);
|
||||
$remainingContentLength = $totalContentLength;
|
||||
|
||||
$offsetIndexOfDecoratedObject = $offsetIndex;
|
||||
$decoratedObjects = [];
|
||||
|
||||
while ($remainingContentLength > 0) {
|
||||
$nextObject = ASNObject::fromBinary($binaryData, $offsetIndex);
|
||||
$remainingContentLength -= $nextObject->getObjectLength();
|
||||
$decoratedObjects[] = $nextObject;
|
||||
}
|
||||
|
||||
if ($remainingContentLength != 0) {
|
||||
throw new ParserException("Context-Specific explicitly tagged object [$tag] starting at offset $offsetIndexOfDecoratedObject specifies a length of $totalContentLength octets but $remainingContentLength remain after parsing the content", $offsetIndexOfDecoratedObject);
|
||||
}
|
||||
|
||||
$parsedObject = new self($tag, ...$decoratedObjects);
|
||||
$parsedObject->setContentLength($totalContentLength);
|
||||
return $parsedObject;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,339 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\ASN1;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* The Identifier encodes the ASN.1 tag (class and number) of the type of a data value.
|
||||
*
|
||||
* Every identifier whose number is in the range 0 to 30 has the following structure:
|
||||
*
|
||||
* Bits: 8 7 6 5 4 3 2 1
|
||||
* | Class | P/C | Tag number |
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* Bits 8 and 7 define the class of this type ( Universal, Application, Context-specific or Private).
|
||||
* Bit 6 encoded whether this type is primitive or constructed
|
||||
* The remaining bits 5 - 1 encode the tag number
|
||||
*/
|
||||
class Identifier
|
||||
{
|
||||
const CLASS_UNIVERSAL = 0x00;
|
||||
const CLASS_APPLICATION = 0x01;
|
||||
const CLASS_CONTEXT_SPECIFIC = 0x02;
|
||||
const CLASS_PRIVATE = 0x03;
|
||||
|
||||
const EOC = 0x00; // unsupported for now
|
||||
const BOOLEAN = 0x01;
|
||||
const INTEGER = 0x02;
|
||||
const BITSTRING = 0x03;
|
||||
const OCTETSTRING = 0x04;
|
||||
const NULL = 0x05;
|
||||
const OBJECT_IDENTIFIER = 0x06;
|
||||
const OBJECT_DESCRIPTOR = 0x07;
|
||||
const EXTERNAL = 0x08; // unsupported for now
|
||||
const REAL = 0x09; // unsupported for now
|
||||
const ENUMERATED = 0x0A;
|
||||
const EMBEDDED_PDV = 0x0B; // unsupported for now
|
||||
const UTF8_STRING = 0x0C;
|
||||
const RELATIVE_OID = 0x0D;
|
||||
// value 0x0E and 0x0F are reserved for future use
|
||||
|
||||
const SEQUENCE = 0x30;
|
||||
const SET = 0x31;
|
||||
const NUMERIC_STRING = 0x12;
|
||||
const PRINTABLE_STRING = 0x13;
|
||||
const T61_STRING = 0x14; // sometimes referred to as TeletextString
|
||||
const VIDEOTEXT_STRING = 0x15;
|
||||
const IA5_STRING = 0x16;
|
||||
const UTC_TIME = 0x17;
|
||||
const GENERALIZED_TIME = 0x18;
|
||||
const GRAPHIC_STRING = 0x19;
|
||||
const VISIBLE_STRING = 0x1A;
|
||||
const GENERAL_STRING = 0x1B;
|
||||
const UNIVERSAL_STRING = 0x1C;
|
||||
const CHARACTER_STRING = 0x1D; // Unrestricted character type
|
||||
const BMP_STRING = 0x1E;
|
||||
|
||||
const LONG_FORM = 0x1F;
|
||||
const IS_CONSTRUCTED = 0x20;
|
||||
|
||||
/**
|
||||
* Creates an identifier. Short form identifiers are returned as integers
|
||||
* for BC, long form identifiers will be returned as a string of octets.
|
||||
*
|
||||
* @param int $class
|
||||
* @param bool $isConstructed
|
||||
* @param int $tagNumber
|
||||
*
|
||||
* @throws Exception if the given arguments are invalid
|
||||
*
|
||||
* @return int|string
|
||||
*/
|
||||
public static function create($class, $isConstructed, $tagNumber)
|
||||
{
|
||||
if (!is_numeric($class) || $class < self::CLASS_UNIVERSAL || $class > self::CLASS_PRIVATE) {
|
||||
throw new Exception(sprintf('Invalid class %d given', $class));
|
||||
}
|
||||
|
||||
if (!is_bool($isConstructed)) {
|
||||
throw new Exception("\$isConstructed must be a boolean value ($isConstructed given)");
|
||||
}
|
||||
|
||||
$tagNumber = self::makeNumeric($tagNumber);
|
||||
if ($tagNumber < 0) {
|
||||
throw new Exception(sprintf('Invalid $tagNumber %d given. You can only use positive integers.', $tagNumber));
|
||||
}
|
||||
|
||||
if ($tagNumber < self::LONG_FORM) {
|
||||
return ($class << 6) | ($isConstructed << 5) | $tagNumber;
|
||||
}
|
||||
|
||||
$firstOctet = ($class << 6) | ($isConstructed << 5) | self::LONG_FORM;
|
||||
|
||||
// Tag numbers formatted in long form are base-128 encoded. See X.609#8.1.2.4
|
||||
return chr($firstOctet).Base128::encode($tagNumber);
|
||||
}
|
||||
|
||||
public static function isConstructed($identifierOctet)
|
||||
{
|
||||
return ($identifierOctet & self::IS_CONSTRUCTED) === self::IS_CONSTRUCTED;
|
||||
}
|
||||
|
||||
public static function isLongForm($identifierOctet)
|
||||
{
|
||||
return ($identifierOctet & self::LONG_FORM) === self::LONG_FORM;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the mapped ASN.1 type with a preceding "ASN.1 ".
|
||||
*
|
||||
* Example: ASN.1 Octet String
|
||||
*
|
||||
* @see Identifier::getShortName()
|
||||
*
|
||||
* @param int|string $identifier
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getName($identifier)
|
||||
{
|
||||
$identifierOctet = self::makeNumeric($identifier);
|
||||
|
||||
$typeName = static::getShortName($identifier);
|
||||
|
||||
if (($identifierOctet & self::LONG_FORM) < self::LONG_FORM) {
|
||||
$typeName = "ASN.1 {$typeName}";
|
||||
}
|
||||
|
||||
return $typeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the short version of the type name.
|
||||
*
|
||||
* If the given identifier octet can be mapped to a known universal type this will
|
||||
* return its name. Else Identifier::getClassDescription() is used to retrieve
|
||||
* information about the identifier.
|
||||
*
|
||||
* @see Identifier::getName()
|
||||
* @see Identifier::getClassDescription()
|
||||
*
|
||||
* @param int|string $identifier
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getShortName($identifier)
|
||||
{
|
||||
$identifierOctet = self::makeNumeric($identifier);
|
||||
|
||||
switch ($identifierOctet) {
|
||||
case self::EOC:
|
||||
return 'End-of-contents octet';
|
||||
case self::BOOLEAN:
|
||||
return 'Boolean';
|
||||
case self::INTEGER:
|
||||
return 'Integer';
|
||||
case self::BITSTRING:
|
||||
return 'Bit String';
|
||||
case self::OCTETSTRING:
|
||||
return 'Octet String';
|
||||
case self::NULL:
|
||||
return 'NULL';
|
||||
case self::OBJECT_IDENTIFIER:
|
||||
return 'Object Identifier';
|
||||
case self::OBJECT_DESCRIPTOR:
|
||||
return 'Object Descriptor';
|
||||
case self::EXTERNAL:
|
||||
return 'External Type';
|
||||
case self::REAL:
|
||||
return 'Real';
|
||||
case self::ENUMERATED:
|
||||
return 'Enumerated';
|
||||
case self::EMBEDDED_PDV:
|
||||
return 'Embedded PDV';
|
||||
case self::UTF8_STRING:
|
||||
return 'UTF8 String';
|
||||
case self::RELATIVE_OID:
|
||||
return 'Relative OID';
|
||||
case self::SEQUENCE:
|
||||
return 'Sequence';
|
||||
case self::SET:
|
||||
return 'Set';
|
||||
case self::NUMERIC_STRING:
|
||||
return 'Numeric String';
|
||||
case self::PRINTABLE_STRING:
|
||||
return 'Printable String';
|
||||
case self::T61_STRING:
|
||||
return 'T61 String';
|
||||
case self::VIDEOTEXT_STRING:
|
||||
return 'Videotext String';
|
||||
case self::IA5_STRING:
|
||||
return 'IA5 String';
|
||||
case self::UTC_TIME:
|
||||
return 'UTC Time';
|
||||
case self::GENERALIZED_TIME:
|
||||
return 'Generalized Time';
|
||||
case self::GRAPHIC_STRING:
|
||||
return 'Graphic String';
|
||||
case self::VISIBLE_STRING:
|
||||
return 'Visible String';
|
||||
case self::GENERAL_STRING:
|
||||
return 'General String';
|
||||
case self::UNIVERSAL_STRING:
|
||||
return 'Universal String';
|
||||
case self::CHARACTER_STRING:
|
||||
return 'Character String';
|
||||
case self::BMP_STRING:
|
||||
return 'BMP String';
|
||||
|
||||
case 0x0E:
|
||||
return 'RESERVED (0x0E)';
|
||||
case 0x0F:
|
||||
return 'RESERVED (0x0F)';
|
||||
|
||||
case self::LONG_FORM:
|
||||
default:
|
||||
$classDescription = self::getClassDescription($identifier);
|
||||
|
||||
if (is_int($identifier)) {
|
||||
$identifier = chr($identifier);
|
||||
}
|
||||
|
||||
return "$classDescription (0x".strtoupper(bin2hex($identifier)).')';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a textual description of the information encoded in a given identifier octet.
|
||||
*
|
||||
* The first three (most significant) bytes are evaluated to determine if this is a
|
||||
* constructed or primitive type and if it is either universal, application, context-specific or
|
||||
* private.
|
||||
*
|
||||
* Example:
|
||||
* Constructed context-specific
|
||||
* Primitive universal
|
||||
*
|
||||
* @param int|string $identifier
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getClassDescription($identifier)
|
||||
{
|
||||
$identifierOctet = self::makeNumeric($identifier);
|
||||
|
||||
if (self::isConstructed($identifierOctet)) {
|
||||
$classDescription = 'Constructed ';
|
||||
} else {
|
||||
$classDescription = 'Primitive ';
|
||||
}
|
||||
$classBits = $identifierOctet >> 6;
|
||||
switch ($classBits) {
|
||||
case self::CLASS_UNIVERSAL:
|
||||
$classDescription .= 'universal';
|
||||
break;
|
||||
case self::CLASS_APPLICATION:
|
||||
$classDescription .= 'application';
|
||||
break;
|
||||
case self::CLASS_CONTEXT_SPECIFIC:
|
||||
$tagNumber = self::getTagNumber($identifier);
|
||||
$classDescription = "[$tagNumber] Context-specific";
|
||||
break;
|
||||
case self::CLASS_PRIVATE:
|
||||
$classDescription .= 'private';
|
||||
break;
|
||||
|
||||
default:
|
||||
return "INVALID IDENTIFIER OCTET: {$identifierOctet}";
|
||||
}
|
||||
|
||||
return $classDescription;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|string $identifier
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function getTagNumber($identifier)
|
||||
{
|
||||
$firstOctet = self::makeNumeric($identifier);
|
||||
$tagNumber = $firstOctet & self::LONG_FORM;
|
||||
|
||||
if ($tagNumber < self::LONG_FORM) {
|
||||
return $tagNumber;
|
||||
}
|
||||
|
||||
if (is_numeric($identifier)) {
|
||||
$identifier = chr($identifier);
|
||||
}
|
||||
return Base128::decode(substr($identifier, 1));
|
||||
}
|
||||
|
||||
public static function isUniversalClass($identifier)
|
||||
{
|
||||
$identifier = self::makeNumeric($identifier);
|
||||
|
||||
return $identifier >> 6 == self::CLASS_UNIVERSAL;
|
||||
}
|
||||
|
||||
public static function isApplicationClass($identifier)
|
||||
{
|
||||
$identifier = self::makeNumeric($identifier);
|
||||
|
||||
return $identifier >> 6 == self::CLASS_APPLICATION;
|
||||
}
|
||||
|
||||
public static function isContextSpecificClass($identifier)
|
||||
{
|
||||
$identifier = self::makeNumeric($identifier);
|
||||
|
||||
return $identifier >> 6 == self::CLASS_CONTEXT_SPECIFIC;
|
||||
}
|
||||
|
||||
public static function isPrivateClass($identifier)
|
||||
{
|
||||
$identifier = self::makeNumeric($identifier);
|
||||
|
||||
return $identifier >> 6 == self::CLASS_PRIVATE;
|
||||
}
|
||||
|
||||
private static function makeNumeric($identifierOctet)
|
||||
{
|
||||
if (!is_numeric($identifierOctet)) {
|
||||
return ord($identifierOctet);
|
||||
} else {
|
||||
return $identifierOctet;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,198 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\ASN1;
|
||||
|
||||
class OID
|
||||
{
|
||||
const RSA_ENCRYPTION = '1.2.840.113549.1.1.1';
|
||||
const MD5_WITH_RSA_ENCRYPTION = '1.2.840.113549.1.1.4';
|
||||
const SHA1_WITH_RSA_SIGNATURE = '1.2.840.113549.1.1.5';
|
||||
const PKCS9_EMAIL = '1.2.840.113549.1.9.1';
|
||||
const PKCS9_UNSTRUCTURED_NAME = '1.2.840.113549.1.9.2';
|
||||
const PKCS9_CONTENT_TYPE = '1.2.840.113549.1.9.3';
|
||||
const PKCS9_MESSAGE_DIGEST = '1.2.840.113549.1.9.4';
|
||||
const PKCS9_SIGNING_TIME = '1.2.840.113549.1.9.5';
|
||||
const PKCS9_EXTENSION_REQUEST = '1.2.840.113549.1.9.14';
|
||||
|
||||
// certificate extension identifier
|
||||
const CERT_EXT_SUBJECT_DIRECTORY_ATTR = '2.5.29.9';
|
||||
const CERT_EXT_SUBJECT_KEY_IDENTIFIER = '2.5.29.14';
|
||||
const CERT_EXT_KEY_USAGE = '2.5.29.15';
|
||||
const CERT_EXT_PRIVATE_KEY_USAGE_PERIOD = '2.5.29.16';
|
||||
const CERT_EXT_SUBJECT_ALT_NAME = '2.5.29.17';
|
||||
const CERT_EXT_ISSUER_ALT_NAME = '2.5.29.18';
|
||||
const CERT_EXT_BASIC_CONSTRAINTS = '2.5.29.19';
|
||||
const CERT_EXT_CRL_NUMBER = '2.5.29.20';
|
||||
const CERT_EXT_REASON_CODE = '2.5.29.21';
|
||||
const CERT_EXT_INVALIDITY_DATE = '2.5.29.24';
|
||||
const CERT_EXT_DELTA_CRL_INDICATOR = '2.5.29.27';
|
||||
const CERT_EXT_ISSUING_DIST_POINT = '2.5.29.28';
|
||||
const CERT_EXT_CERT_ISSUER = '2.5.29.29';
|
||||
const CERT_EXT_NAME_CONSTRAINTS = '2.5.29.30';
|
||||
const CERT_EXT_CRL_DISTRIBUTION_POINTS = '2.5.29.31';
|
||||
const CERT_EXT_CERT_POLICIES = '2.5.29.32';
|
||||
const CERT_EXT_AUTHORITY_KEY_IDENTIFIER = '2.5.29.35';
|
||||
const CERT_EXT_EXTENDED_KEY_USAGE = '2.5.29.37';
|
||||
|
||||
// standard certificate files
|
||||
const COMMON_NAME = '2.5.4.3';
|
||||
const SURNAME = '2.5.4.4';
|
||||
const SERIAL_NUMBER = '2.5.4.5';
|
||||
const COUNTRY_NAME = '2.5.4.6';
|
||||
const LOCALITY_NAME = '2.5.4.7';
|
||||
const STATE_OR_PROVINCE_NAME = '2.5.4.8';
|
||||
const STREET_ADDRESS = '2.5.4.9';
|
||||
const ORGANIZATION_NAME = '2.5.4.10';
|
||||
const OU_NAME = '2.5.4.11';
|
||||
const TITLE = '2.5.4.12';
|
||||
const DESCRIPTION = '2.5.4.13';
|
||||
const POSTAL_ADDRESS = '2.5.4.16';
|
||||
const POSTAL_CODE = '2.5.4.17';
|
||||
const AUTHORITY_REVOCATION_LIST = '2.5.4.38';
|
||||
|
||||
const AUTHORITY_INFORMATION_ACCESS = '1.3.6.1.5.5.7.1.1';
|
||||
|
||||
/**
|
||||
* Returns the name of the given object identifier.
|
||||
*
|
||||
* Some OIDs are saved as class constants in this class.
|
||||
* If the wanted oidString is not among them, this method will
|
||||
* query http://oid-info.com for the right name.
|
||||
* This behavior can be suppressed by setting the second method parameter to false.
|
||||
*
|
||||
* @param string $oidString
|
||||
* @param bool $loadFromWeb
|
||||
*
|
||||
* @see self::loadFromWeb($oidString)
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getName($oidString, $loadFromWeb = true)
|
||||
{
|
||||
switch ($oidString) {
|
||||
case self::RSA_ENCRYPTION:
|
||||
return 'RSA Encryption';
|
||||
case self::MD5_WITH_RSA_ENCRYPTION:
|
||||
return 'MD5 with RSA Encryption';
|
||||
case self::SHA1_WITH_RSA_SIGNATURE:
|
||||
return 'SHA-1 with RSA Signature';
|
||||
|
||||
case self::PKCS9_EMAIL:
|
||||
return 'PKCS #9 Email Address';
|
||||
case self::PKCS9_UNSTRUCTURED_NAME:
|
||||
return 'PKCS #9 Unstructured Name';
|
||||
case self::PKCS9_CONTENT_TYPE:
|
||||
return 'PKCS #9 Content Type';
|
||||
case self::PKCS9_MESSAGE_DIGEST:
|
||||
return 'PKCS #9 Message Digest';
|
||||
case self::PKCS9_SIGNING_TIME:
|
||||
return 'PKCS #9 Signing Time';
|
||||
|
||||
case self::COMMON_NAME:
|
||||
return 'Common Name';
|
||||
case self::SURNAME:
|
||||
return 'Surname';
|
||||
case self::SERIAL_NUMBER:
|
||||
return 'Serial Number';
|
||||
case self::COUNTRY_NAME:
|
||||
return 'Country Name';
|
||||
case self::LOCALITY_NAME:
|
||||
return 'Locality Name';
|
||||
case self::STATE_OR_PROVINCE_NAME:
|
||||
return 'State or Province Name';
|
||||
case self::STREET_ADDRESS:
|
||||
return 'Street Address';
|
||||
case self::ORGANIZATION_NAME:
|
||||
return 'Organization Name';
|
||||
case self::OU_NAME:
|
||||
return 'Organization Unit Name';
|
||||
case self::TITLE:
|
||||
return 'Title';
|
||||
case self::DESCRIPTION:
|
||||
return 'Description';
|
||||
case self::POSTAL_ADDRESS:
|
||||
return 'Postal Address';
|
||||
case self::POSTAL_CODE:
|
||||
return 'Postal Code';
|
||||
case self::AUTHORITY_REVOCATION_LIST:
|
||||
return 'Authority Revocation List';
|
||||
|
||||
case self::CERT_EXT_SUBJECT_DIRECTORY_ATTR:
|
||||
return 'Subject directory attributes';
|
||||
case self::CERT_EXT_SUBJECT_KEY_IDENTIFIER:
|
||||
return 'Subject key identifier';
|
||||
case self::CERT_EXT_KEY_USAGE:
|
||||
return 'Key usage certificate extension';
|
||||
case self::CERT_EXT_PRIVATE_KEY_USAGE_PERIOD:
|
||||
return 'Private key usage';
|
||||
case self::CERT_EXT_SUBJECT_ALT_NAME:
|
||||
return 'Subject alternative name (SAN)';
|
||||
case self::CERT_EXT_ISSUER_ALT_NAME:
|
||||
return 'Issuer alternative name';
|
||||
case self::CERT_EXT_BASIC_CONSTRAINTS:
|
||||
return 'Basic constraints';
|
||||
case self::CERT_EXT_CRL_NUMBER:
|
||||
return 'CRL number';
|
||||
case self::CERT_EXT_REASON_CODE:
|
||||
return 'Reason code';
|
||||
case self::CERT_EXT_INVALIDITY_DATE:
|
||||
return 'Invalidity code';
|
||||
case self::CERT_EXT_DELTA_CRL_INDICATOR:
|
||||
return 'Delta CRL indicator';
|
||||
case self::CERT_EXT_ISSUING_DIST_POINT:
|
||||
return 'Issuing distribution point';
|
||||
case self::CERT_EXT_CERT_ISSUER:
|
||||
return 'Certificate issuer';
|
||||
case self::CERT_EXT_NAME_CONSTRAINTS:
|
||||
return 'Name constraints';
|
||||
case self::CERT_EXT_CRL_DISTRIBUTION_POINTS:
|
||||
return 'CRL distribution points';
|
||||
case self::CERT_EXT_CERT_POLICIES:
|
||||
return 'Certificate policies ';
|
||||
case self::CERT_EXT_AUTHORITY_KEY_IDENTIFIER:
|
||||
return 'Authority key identifier';
|
||||
case self::CERT_EXT_EXTENDED_KEY_USAGE:
|
||||
return 'Extended key usage';
|
||||
case self::AUTHORITY_INFORMATION_ACCESS:
|
||||
return 'Certificate Authority Information Access (AIA)';
|
||||
|
||||
default:
|
||||
if ($loadFromWeb) {
|
||||
return self::loadFromWeb($oidString);
|
||||
} else {
|
||||
return $oidString;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function loadFromWeb($oidString)
|
||||
{
|
||||
$ch = curl_init("http://oid-info.com/get/{$oidString}");
|
||||
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_HEADER, 0);
|
||||
|
||||
$contents = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
|
||||
// This pattern needs to be updated as soon as the website layout of oid-info.com changes
|
||||
preg_match_all('#<tt>(.+)\(\d+\)</tt>#si', $contents, $oidName);
|
||||
|
||||
if (empty($oidName[1])) {
|
||||
return "{$oidString} (unknown)";
|
||||
}
|
||||
|
||||
$oidName = ucfirst(strtolower(preg_replace('/([A-Z][a-z])/', ' $1', $oidName[1][0])));
|
||||
$oidName = str_replace('-', ' ', $oidName);
|
||||
|
||||
return "{$oidName} ({$oidString})";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\ASN1;
|
||||
|
||||
use FG\ASN1\Exception\ParserException;
|
||||
|
||||
/**
|
||||
* The Parsable interface describes classes that can be parsed from their binary DER representation.
|
||||
*/
|
||||
interface Parsable
|
||||
{
|
||||
/**
|
||||
* Parse an instance of this class from its binary DER encoded representation.
|
||||
*
|
||||
* @param string $binaryData
|
||||
* @param int $offsetIndex the offset at which parsing of the $binaryData is started. This parameter ill be modified
|
||||
* to contain the offset index of the next object after this object has been parsed
|
||||
*
|
||||
* @throws ParserException if the given binary data is either invalid or not currently supported
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function fromBinary(&$binaryData, &$offsetIndex = null);
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\ASN1;
|
||||
|
||||
use Exception;
|
||||
use FG\ASN1\Exception\ParserException;
|
||||
use FG\ASN1\Universal\Sequence;
|
||||
|
||||
class TemplateParser
|
||||
{
|
||||
/**
|
||||
* @param string $data
|
||||
* @param array $template
|
||||
* @return \FG\ASN1\ASNObject|Sequence
|
||||
* @throws ParserException if there was an issue parsing
|
||||
*/
|
||||
public function parseBase64($data, array $template)
|
||||
{
|
||||
// TODO test with invalid data
|
||||
return $this->parseBinary(base64_decode($data), $template);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $binary
|
||||
* @param array $template
|
||||
* @return \FG\ASN1\ASNObject|Sequence
|
||||
* @throws ParserException if there was an issue parsing
|
||||
*/
|
||||
public function parseBinary($binary, array $template)
|
||||
{
|
||||
$parsedObject = ASNObject::fromBinary($binary);
|
||||
|
||||
foreach ($template as $key => $value) {
|
||||
$this->validate($parsedObject, $key, $value);
|
||||
}
|
||||
|
||||
return $parsedObject;
|
||||
}
|
||||
|
||||
private function validate(ASNObject $object, $key, $value)
|
||||
{
|
||||
if (is_array($value)) {
|
||||
$this->assertTypeId($key, $object);
|
||||
|
||||
/* @var Construct $object */
|
||||
foreach ($value as $key => $child) {
|
||||
$this->validate($object->current(), $key, $child);
|
||||
$object->next();
|
||||
}
|
||||
} else {
|
||||
$this->assertTypeId($value, $object);
|
||||
}
|
||||
}
|
||||
|
||||
private function assertTypeId($expectedTypeId, ASNObject $object)
|
||||
{
|
||||
$actualType = $object->getType();
|
||||
if ($expectedTypeId != $actualType) {
|
||||
throw new Exception("Expected type ($expectedTypeId) does not match actual type ($actualType");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\ASN1\Universal;
|
||||
|
||||
use FG\ASN1\AbstractString;
|
||||
use FG\ASN1\Identifier;
|
||||
|
||||
class BMPString extends AbstractString
|
||||
{
|
||||
/**
|
||||
* Creates a new ASN.1 BMP String.
|
||||
*
|
||||
* BMPString is a subtype of UniversalString that has its own
|
||||
* unique tag and contains only the characters in the
|
||||
* Basic Multilingual Plane (those corresponding to the first
|
||||
* 64K-2 cells, less cells whose encoding is used to address
|
||||
* characters outside the Basic Multilingual Plane) of ISO/IEC 10646-1.
|
||||
*
|
||||
* TODO The encodable characters of this type are not yet checked.
|
||||
*
|
||||
* @param string $string
|
||||
*/
|
||||
public function __construct($string)
|
||||
{
|
||||
$this->value = $string;
|
||||
$this->allowAll();
|
||||
}
|
||||
|
||||
public function getType()
|
||||
{
|
||||
return Identifier::BMP_STRING;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\ASN1\Universal;
|
||||
|
||||
use Exception;
|
||||
use FG\ASN1\Exception\ParserException;
|
||||
use FG\ASN1\Parsable;
|
||||
use FG\ASN1\Identifier;
|
||||
|
||||
class BitString extends OctetString implements Parsable
|
||||
{
|
||||
private $nrOfUnusedBits;
|
||||
|
||||
/**
|
||||
* Creates a new ASN.1 BitString object.
|
||||
*
|
||||
* @param string|int $value Either the hexadecimal value as a string (spaces are allowed - leading 0x is optional) or a numeric value
|
||||
* @param int $nrOfUnusedBits the number of unused bits in the last octet [optional].
|
||||
*
|
||||
* @throws Exception if the second parameter is no positive numeric value
|
||||
*/
|
||||
public function __construct($value, $nrOfUnusedBits = 0)
|
||||
{
|
||||
parent::__construct($value);
|
||||
|
||||
if (!is_numeric($nrOfUnusedBits) || $nrOfUnusedBits < 0) {
|
||||
throw new Exception('BitString: second parameter needs to be a positive number (or zero)!');
|
||||
}
|
||||
|
||||
$this->nrOfUnusedBits = $nrOfUnusedBits;
|
||||
}
|
||||
|
||||
public function getType()
|
||||
{
|
||||
return Identifier::BITSTRING;
|
||||
}
|
||||
|
||||
protected function calculateContentLength()
|
||||
{
|
||||
// add one to the length for the first octet which encodes the number of unused bits in the last octet
|
||||
return parent::calculateContentLength() + 1;
|
||||
}
|
||||
|
||||
protected function getEncodedValue()
|
||||
{
|
||||
// the first octet determines the number of unused bits
|
||||
$nrOfUnusedBitsOctet = chr($this->nrOfUnusedBits);
|
||||
$actualContent = parent::getEncodedValue();
|
||||
|
||||
return $nrOfUnusedBitsOctet.$actualContent;
|
||||
}
|
||||
|
||||
public function getNumberOfUnusedBits()
|
||||
{
|
||||
return $this->nrOfUnusedBits;
|
||||
}
|
||||
|
||||
public static function fromBinary(&$binaryData, &$offsetIndex = 0)
|
||||
{
|
||||
self::parseIdentifier($binaryData[$offsetIndex], Identifier::BITSTRING, $offsetIndex++);
|
||||
$contentLength = self::parseContentLength($binaryData, $offsetIndex, 2);
|
||||
|
||||
$nrOfUnusedBits = ord($binaryData[$offsetIndex]);
|
||||
$value = substr($binaryData, $offsetIndex + 1, $contentLength - 1);
|
||||
|
||||
if ($nrOfUnusedBits > 7 || // no less than 1 used, otherwise non-minimal
|
||||
($contentLength - 1) == 1 && $nrOfUnusedBits > 0 || // content length only 1, no
|
||||
(ord($value[strlen($value)-1])&((1<<$nrOfUnusedBits)-1)) != 0 // unused bits set
|
||||
) {
|
||||
throw new ParserException("Can not parse bit string with invalid padding", $offsetIndex);
|
||||
}
|
||||
|
||||
$offsetIndex += $contentLength;
|
||||
|
||||
$parsedObject = new self(bin2hex($value), $nrOfUnusedBits);
|
||||
$parsedObject->setContentLength($contentLength);
|
||||
|
||||
return $parsedObject;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\ASN1\Universal;
|
||||
|
||||
use FG\ASN1\ASNObject;
|
||||
use FG\ASN1\Parsable;
|
||||
use FG\ASN1\Identifier;
|
||||
use FG\ASN1\Exception\ParserException;
|
||||
|
||||
class Boolean extends ASNObject implements Parsable
|
||||
{
|
||||
private $value;
|
||||
|
||||
/**
|
||||
* @param bool $value
|
||||
*/
|
||||
public function __construct($value)
|
||||
{
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
public function getType()
|
||||
{
|
||||
return Identifier::BOOLEAN;
|
||||
}
|
||||
|
||||
protected function calculateContentLength()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
protected function getEncodedValue()
|
||||
{
|
||||
if ($this->value == false) {
|
||||
return chr(0x00);
|
||||
} else {
|
||||
return chr(0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
public function getContent()
|
||||
{
|
||||
if ($this->value == true) {
|
||||
return 'TRUE';
|
||||
} else {
|
||||
return 'FALSE';
|
||||
}
|
||||
}
|
||||
|
||||
public static function fromBinary(&$binaryData, &$offsetIndex = 0)
|
||||
{
|
||||
self::parseIdentifier($binaryData[$offsetIndex], Identifier::BOOLEAN, $offsetIndex++);
|
||||
$contentLength = self::parseContentLength($binaryData, $offsetIndex);
|
||||
|
||||
if ($contentLength != 1) {
|
||||
throw new ParserException("An ASN.1 Boolean should not have a length other than one. Extracted length was {$contentLength}", $offsetIndex);
|
||||
}
|
||||
|
||||
$value = ord($binaryData[$offsetIndex++]);
|
||||
$booleanValue = $value == 0xFF ? true : false;
|
||||
|
||||
$parsedObject = new self($booleanValue);
|
||||
$parsedObject->setContentLength($contentLength);
|
||||
|
||||
return $parsedObject;
|
||||
}
|
||||
}
|
28
lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/CharacterString.php
vendored
Normal file
28
lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/CharacterString.php
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\ASN1\Universal;
|
||||
|
||||
use FG\ASN1\AbstractString;
|
||||
use FG\ASN1\Identifier;
|
||||
|
||||
class CharacterString extends AbstractString
|
||||
{
|
||||
public function __construct($string)
|
||||
{
|
||||
$this->value = $string;
|
||||
$this->allowAll();
|
||||
}
|
||||
|
||||
public function getType()
|
||||
{
|
||||
return Identifier::CHARACTER_STRING;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\ASN1\Universal;
|
||||
|
||||
use FG\ASN1\Identifier;
|
||||
|
||||
class Enumerated extends Integer
|
||||
{
|
||||
public function getType()
|
||||
{
|
||||
return Identifier::ENUMERATED;
|
||||
}
|
||||
}
|
34
lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/GeneralString.php
vendored
Normal file
34
lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/GeneralString.php
vendored
Normal file
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\ASN1\Universal;
|
||||
|
||||
use FG\ASN1\AbstractString;
|
||||
use FG\ASN1\Identifier;
|
||||
|
||||
class GeneralString extends AbstractString
|
||||
{
|
||||
/**
|
||||
* Creates a new ASN.1 GeneralString.
|
||||
* TODO The encodable characters of this type are not yet checked.
|
||||
*
|
||||
* @param string $string
|
||||
*/
|
||||
public function __construct($string)
|
||||
{
|
||||
$this->value = $string;
|
||||
$this->allowAll();
|
||||
}
|
||||
|
||||
public function getType()
|
||||
{
|
||||
return Identifier::GENERAL_STRING;
|
||||
}
|
||||
}
|
134
lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/GeneralizedTime.php
vendored
Normal file
134
lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/GeneralizedTime.php
vendored
Normal file
|
@ -0,0 +1,134 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\ASN1\Universal;
|
||||
|
||||
use FG\ASN1\AbstractTime;
|
||||
use FG\ASN1\Parsable;
|
||||
use FG\ASN1\Identifier;
|
||||
use FG\ASN1\Exception\ParserException;
|
||||
|
||||
/**
|
||||
* This ASN.1 universal type contains date and time information according to ISO 8601.
|
||||
*
|
||||
* The type consists of values representing:
|
||||
* a) a calendar date, as defined in ISO 8601; and
|
||||
* b) a time of day, to any of the precisions defined in ISO 8601, except for the hours value 24 which shall not be used; and
|
||||
* c) the local time differential factor as defined in ISO 8601.
|
||||
*
|
||||
* Decoding of this type will accept the Basic Encoding Rules (BER)
|
||||
* The encoding will comply with the Distinguished Encoding Rules (DER).
|
||||
*/
|
||||
class GeneralizedTime extends AbstractTime implements Parsable
|
||||
{
|
||||
private $microseconds;
|
||||
|
||||
public function __construct($dateTime = null, $dateTimeZone = 'UTC')
|
||||
{
|
||||
parent::__construct($dateTime, $dateTimeZone);
|
||||
$this->microseconds = $this->value->format('u');
|
||||
if ($this->containsFractionalSecondsElement()) {
|
||||
// DER requires us to remove trailing zeros
|
||||
$this->microseconds = preg_replace('/([1-9]+)0+$/', '$1', $this->microseconds);
|
||||
}
|
||||
}
|
||||
|
||||
public function getType()
|
||||
{
|
||||
return Identifier::GENERALIZED_TIME;
|
||||
}
|
||||
|
||||
protected function calculateContentLength()
|
||||
{
|
||||
$contentSize = 15; // YYYYMMDDHHmmSSZ
|
||||
|
||||
if ($this->containsFractionalSecondsElement()) {
|
||||
$contentSize += 1 + strlen($this->microseconds);
|
||||
}
|
||||
|
||||
return $contentSize;
|
||||
}
|
||||
|
||||
public function containsFractionalSecondsElement()
|
||||
{
|
||||
return intval($this->microseconds) > 0;
|
||||
}
|
||||
|
||||
protected function getEncodedValue()
|
||||
{
|
||||
$encodedContent = $this->value->format('YmdHis');
|
||||
if ($this->containsFractionalSecondsElement()) {
|
||||
$encodedContent .= ".{$this->microseconds}";
|
||||
}
|
||||
|
||||
return $encodedContent.'Z';
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
if ($this->containsFractionalSecondsElement()) {
|
||||
return $this->value->format("Y-m-d\tH:i:s.uP");
|
||||
} else {
|
||||
return $this->value->format("Y-m-d\tH:i:sP");
|
||||
}
|
||||
}
|
||||
|
||||
public static function fromBinary(&$binaryData, &$offsetIndex = 0)
|
||||
{
|
||||
self::parseIdentifier($binaryData[$offsetIndex], Identifier::GENERALIZED_TIME, $offsetIndex++);
|
||||
$lengthOfMinimumTimeString = 14; // YYYYMMDDHHmmSS
|
||||
$contentLength = self::parseContentLength($binaryData, $offsetIndex, $lengthOfMinimumTimeString);
|
||||
$maximumBytesToRead = $contentLength;
|
||||
|
||||
$format = 'YmdGis';
|
||||
$content = substr($binaryData, $offsetIndex, $contentLength);
|
||||
$dateTimeString = substr($content, 0, $lengthOfMinimumTimeString);
|
||||
$offsetIndex += $lengthOfMinimumTimeString;
|
||||
$maximumBytesToRead -= $lengthOfMinimumTimeString;
|
||||
|
||||
if ($contentLength == $lengthOfMinimumTimeString) {
|
||||
$localTimeZone = new \DateTimeZone(date_default_timezone_get());
|
||||
$dateTime = \DateTime::createFromFormat($format, $dateTimeString, $localTimeZone);
|
||||
} else {
|
||||
if ($binaryData[$offsetIndex] == '.') {
|
||||
$maximumBytesToRead--; // account for the '.'
|
||||
$nrOfFractionalSecondElements = 1; // account for the '.'
|
||||
|
||||
while ($maximumBytesToRead > 0
|
||||
&& $binaryData[$offsetIndex + $nrOfFractionalSecondElements] != '+'
|
||||
&& $binaryData[$offsetIndex + $nrOfFractionalSecondElements] != '-'
|
||||
&& $binaryData[$offsetIndex + $nrOfFractionalSecondElements] != 'Z') {
|
||||
$nrOfFractionalSecondElements++;
|
||||
$maximumBytesToRead--;
|
||||
}
|
||||
|
||||
$dateTimeString .= substr($binaryData, $offsetIndex, $nrOfFractionalSecondElements);
|
||||
$offsetIndex += $nrOfFractionalSecondElements;
|
||||
$format .= '.u';
|
||||
}
|
||||
|
||||
$dateTime = \DateTime::createFromFormat($format, $dateTimeString, new \DateTimeZone('UTC'));
|
||||
|
||||
if ($maximumBytesToRead > 0) {
|
||||
if ($binaryData[$offsetIndex] == '+'
|
||||
|| $binaryData[$offsetIndex] == '-') {
|
||||
$dateTime = static::extractTimeZoneData($binaryData, $offsetIndex, $dateTime);
|
||||
} elseif ($binaryData[$offsetIndex++] != 'Z') {
|
||||
throw new ParserException('Invalid ISO 8601 Time String', $offsetIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$parsedObject = new self($dateTime);
|
||||
$parsedObject->setContentLength($contentLength);
|
||||
|
||||
return $parsedObject;
|
||||
}
|
||||
}
|
34
lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/GraphicString.php
vendored
Normal file
34
lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/GraphicString.php
vendored
Normal file
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\ASN1\Universal;
|
||||
|
||||
use FG\ASN1\AbstractString;
|
||||
use FG\ASN1\Identifier;
|
||||
|
||||
class GraphicString extends AbstractString
|
||||
{
|
||||
/**
|
||||
* Creates a new ASN.1 Graphic String.
|
||||
* TODO The encodable characters of this type are not yet checked.
|
||||
*
|
||||
* @param string $string
|
||||
*/
|
||||
public function __construct($string)
|
||||
{
|
||||
$this->value = $string;
|
||||
$this->allowAll();
|
||||
}
|
||||
|
||||
public function getType()
|
||||
{
|
||||
return Identifier::GRAPHIC_STRING;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\ASN1\Universal;
|
||||
|
||||
use FG\ASN1\AbstractString;
|
||||
use FG\ASN1\Identifier;
|
||||
|
||||
/**
|
||||
* The International Alphabet No.5 (IA5) references the encoding of the ASCII characters.
|
||||
*
|
||||
* Each character in the data is encoded as 1 byte.
|
||||
*/
|
||||
class IA5String extends AbstractString
|
||||
{
|
||||
public function __construct($string)
|
||||
{
|
||||
parent::__construct($string);
|
||||
for ($i = 1; $i < 128; $i++) {
|
||||
$this->allowCharacter(chr($i));
|
||||
}
|
||||
}
|
||||
|
||||
public function getType()
|
||||
{
|
||||
return Identifier::IA5_STRING;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\ASN1\Universal;
|
||||
|
||||
use Exception;
|
||||
use FG\Utility\BigInteger;
|
||||
use FG\ASN1\Exception\ParserException;
|
||||
use FG\ASN1\ASNObject;
|
||||
use FG\ASN1\Parsable;
|
||||
use FG\ASN1\Identifier;
|
||||
|
||||
class Integer extends ASNObject implements Parsable
|
||||
{
|
||||
/** @var int */
|
||||
private $value;
|
||||
|
||||
/**
|
||||
* @param int $value
|
||||
*
|
||||
* @throws Exception if the value is not numeric
|
||||
*/
|
||||
public function __construct($value)
|
||||
{
|
||||
if (is_numeric($value) == false) {
|
||||
throw new Exception("Invalid VALUE [{$value}] for ASN1_INTEGER");
|
||||
}
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
public function getType()
|
||||
{
|
||||
return Identifier::INTEGER;
|
||||
}
|
||||
|
||||
public function getContent()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
protected function calculateContentLength()
|
||||
{
|
||||
return strlen($this->getEncodedValue());
|
||||
}
|
||||
|
||||
protected function getEncodedValue()
|
||||
{
|
||||
$value = BigInteger::create($this->value, 10);
|
||||
$negative = $value->compare(0) < 0;
|
||||
if ($negative) {
|
||||
$value = $value->absoluteValue();
|
||||
$limit = 0x80;
|
||||
} else {
|
||||
$limit = 0x7f;
|
||||
}
|
||||
|
||||
$mod = 0xff+1;
|
||||
$values = [];
|
||||
while($value->compare($limit) > 0) {
|
||||
$values[] = $value->modulus($mod)->toInteger();
|
||||
$value = $value->shiftRight(8);
|
||||
}
|
||||
|
||||
$values[] = $value->modulus($mod)->toInteger();
|
||||
$numValues = count($values);
|
||||
|
||||
if ($negative) {
|
||||
for ($i = 0; $i < $numValues; $i++) {
|
||||
$values[$i] = 0xff - $values[$i];
|
||||
}
|
||||
for ($i = 0; $i < $numValues; $i++) {
|
||||
$values[$i] += 1;
|
||||
if ($values[$i] <= 0xff) {
|
||||
break;
|
||||
}
|
||||
assert($i != $numValues - 1);
|
||||
$values[$i] = 0;
|
||||
}
|
||||
if ($values[$numValues - 1] == 0x7f) {
|
||||
$values[] = 0xff;
|
||||
}
|
||||
}
|
||||
$values = array_reverse($values);
|
||||
$r = pack("C*", ...$values);
|
||||
return $r;
|
||||
}
|
||||
|
||||
private static function ensureMinimalEncoding($binaryData, $offsetIndex)
|
||||
{
|
||||
// All the first nine bits cannot equal 0 or 1, which would
|
||||
// be non-minimal encoding for positive and negative integers respectively
|
||||
if ((ord($binaryData[$offsetIndex]) == 0x00 && (ord($binaryData[$offsetIndex+1]) & 0x80) == 0) ||
|
||||
(ord($binaryData[$offsetIndex]) == 0xff && (ord($binaryData[$offsetIndex+1]) & 0x80) == 0x80)) {
|
||||
throw new ParserException("Integer not minimally encoded", $offsetIndex);
|
||||
}
|
||||
}
|
||||
|
||||
public static function fromBinary(&$binaryData, &$offsetIndex = 0)
|
||||
{
|
||||
$parsedObject = new static(0);
|
||||
self::parseIdentifier($binaryData[$offsetIndex], $parsedObject->getType(), $offsetIndex++);
|
||||
$contentLength = self::parseContentLength($binaryData, $offsetIndex, 1);
|
||||
|
||||
if ($contentLength > 1) {
|
||||
self::ensureMinimalEncoding($binaryData, $offsetIndex);
|
||||
}
|
||||
$isNegative = (ord($binaryData[$offsetIndex]) & 0x80) != 0x00;
|
||||
$number = BigInteger::create(ord($binaryData[$offsetIndex++]) & 0x7F);
|
||||
|
||||
for ($i = 0; $i < $contentLength - 1; $i++) {
|
||||
$number = $number->multiply(0x100)->add(ord($binaryData[$offsetIndex++]));
|
||||
}
|
||||
|
||||
if ($isNegative) {
|
||||
$number = $number->subtract(BigInteger::create(2)->toPower(8 * $contentLength - 1));
|
||||
}
|
||||
|
||||
$parsedObject = new static((string)$number);
|
||||
$parsedObject->setContentLength($contentLength);
|
||||
|
||||
return $parsedObject;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\ASN1\Universal;
|
||||
|
||||
use FG\ASN1\ASNObject;
|
||||
use FG\ASN1\Parsable;
|
||||
use FG\ASN1\Identifier;
|
||||
use FG\ASN1\Exception\ParserException;
|
||||
|
||||
class NullObject extends ASNObject implements Parsable
|
||||
{
|
||||
public function getType()
|
||||
{
|
||||
return Identifier::NULL;
|
||||
}
|
||||
|
||||
protected function calculateContentLength()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected function getEncodedValue()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getContent()
|
||||
{
|
||||
return 'NULL';
|
||||
}
|
||||
|
||||
public static function fromBinary(&$binaryData, &$offsetIndex = 0)
|
||||
{
|
||||
self::parseIdentifier($binaryData[$offsetIndex], Identifier::NULL, $offsetIndex++);
|
||||
$contentLength = self::parseContentLength($binaryData, $offsetIndex);
|
||||
|
||||
if ($contentLength != 0) {
|
||||
throw new ParserException("An ASN.1 Null should not have a length other than zero. Extracted length was {$contentLength}", $offsetIndex);
|
||||
}
|
||||
|
||||
$parsedObject = new self();
|
||||
$parsedObject->setContentLength(0);
|
||||
|
||||
return $parsedObject;
|
||||
}
|
||||
}
|
38
lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/NumericString.php
vendored
Normal file
38
lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/NumericString.php
vendored
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\ASN1\Universal;
|
||||
|
||||
use FG\ASN1\AbstractString;
|
||||
use FG\ASN1\Identifier;
|
||||
|
||||
class NumericString extends AbstractString
|
||||
{
|
||||
/**
|
||||
* Creates a new ASN.1 NumericString.
|
||||
*
|
||||
* The following characters are permitted:
|
||||
* Digits 0,1, ... 9
|
||||
* SPACE (space)
|
||||
*
|
||||
* @param string $string
|
||||
*/
|
||||
public function __construct($string)
|
||||
{
|
||||
$this->value = $string;
|
||||
$this->allowNumbers();
|
||||
$this->allowSpaces();
|
||||
}
|
||||
|
||||
public function getType()
|
||||
{
|
||||
return Identifier::NUMERIC_STRING;
|
||||
}
|
||||
}
|
26
lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/ObjectDescriptor.php
vendored
Normal file
26
lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/ObjectDescriptor.php
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\ASN1\Universal;
|
||||
|
||||
use FG\ASN1\Identifier;
|
||||
|
||||
class ObjectDescriptor extends GraphicString
|
||||
{
|
||||
public function __construct($objectDescription)
|
||||
{
|
||||
parent::__construct($objectDescription);
|
||||
}
|
||||
|
||||
public function getType()
|
||||
{
|
||||
return Identifier::OBJECT_DESCRIPTOR;
|
||||
}
|
||||
}
|
138
lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/ObjectIdentifier.php
vendored
Normal file
138
lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/ObjectIdentifier.php
vendored
Normal file
|
@ -0,0 +1,138 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\ASN1\Universal;
|
||||
|
||||
use Exception;
|
||||
use FG\ASN1\Base128;
|
||||
use FG\ASN1\OID;
|
||||
use FG\ASN1\ASNObject;
|
||||
use FG\ASN1\Parsable;
|
||||
use FG\ASN1\Identifier;
|
||||
use FG\ASN1\Exception\ParserException;
|
||||
|
||||
class ObjectIdentifier extends ASNObject implements Parsable
|
||||
{
|
||||
protected $subIdentifiers;
|
||||
protected $value;
|
||||
|
||||
public function __construct($value)
|
||||
{
|
||||
$this->subIdentifiers = explode('.', $value);
|
||||
$nrOfSubIdentifiers = count($this->subIdentifiers);
|
||||
|
||||
for ($i = 0; $i < $nrOfSubIdentifiers; $i++) {
|
||||
if (is_numeric($this->subIdentifiers[$i])) {
|
||||
// enforce the integer type
|
||||
$this->subIdentifiers[$i] = intval($this->subIdentifiers[$i]);
|
||||
} else {
|
||||
throw new Exception("[{$value}] is no valid object identifier (sub identifier ".($i + 1).' is not numeric)!');
|
||||
}
|
||||
}
|
||||
|
||||
// Merge the first to arcs of the OID registration tree (per ASN definition!)
|
||||
if ($nrOfSubIdentifiers >= 2) {
|
||||
$this->subIdentifiers[1] = ($this->subIdentifiers[0] * 40) + $this->subIdentifiers[1];
|
||||
unset($this->subIdentifiers[0]);
|
||||
}
|
||||
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
public function getContent()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
public function getType()
|
||||
{
|
||||
return Identifier::OBJECT_IDENTIFIER;
|
||||
}
|
||||
|
||||
protected function calculateContentLength()
|
||||
{
|
||||
$length = 0;
|
||||
foreach ($this->subIdentifiers as $subIdentifier) {
|
||||
do {
|
||||
$subIdentifier = $subIdentifier >> 7;
|
||||
$length++;
|
||||
} while ($subIdentifier > 0);
|
||||
}
|
||||
|
||||
return $length;
|
||||
}
|
||||
|
||||
protected function getEncodedValue()
|
||||
{
|
||||
$encodedValue = '';
|
||||
foreach ($this->subIdentifiers as $subIdentifier) {
|
||||
$encodedValue .= Base128::encode($subIdentifier);
|
||||
}
|
||||
|
||||
return $encodedValue;
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return OID::getName($this->value);
|
||||
}
|
||||
|
||||
public static function fromBinary(&$binaryData, &$offsetIndex = 0)
|
||||
{
|
||||
self::parseIdentifier($binaryData[$offsetIndex], Identifier::OBJECT_IDENTIFIER, $offsetIndex++);
|
||||
$contentLength = self::parseContentLength($binaryData, $offsetIndex, 1);
|
||||
|
||||
$firstOctet = ord($binaryData[$offsetIndex++]);
|
||||
$oidString = floor($firstOctet / 40).'.'.($firstOctet % 40);
|
||||
$oidString .= '.'.self::parseOid($binaryData, $offsetIndex, $contentLength - 1);
|
||||
|
||||
$parsedObject = new self($oidString);
|
||||
$parsedObject->setContentLength($contentLength);
|
||||
|
||||
return $parsedObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an object identifier except for the first octet, which is parsed
|
||||
* differently. This way relative object identifiers can also be parsed
|
||||
* using this.
|
||||
*
|
||||
* @param $binaryData
|
||||
* @param $offsetIndex
|
||||
* @param $octetsToRead
|
||||
*
|
||||
* @throws ParserException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected static function parseOid(&$binaryData, &$offsetIndex, $octetsToRead)
|
||||
{
|
||||
$oid = '';
|
||||
|
||||
while ($octetsToRead > 0) {
|
||||
$octets = '';
|
||||
|
||||
do {
|
||||
if (0 === $octetsToRead) {
|
||||
throw new ParserException('Malformed ASN.1 Object Identifier', $offsetIndex - 1);
|
||||
}
|
||||
|
||||
$octetsToRead--;
|
||||
$octet = $binaryData[$offsetIndex++];
|
||||
$octets .= $octet;
|
||||
} while (ord($octet) & 0x80);
|
||||
|
||||
$oid .= sprintf('%d.', Base128::decode($octets));
|
||||
}
|
||||
|
||||
// Remove trailing '.'
|
||||
return substr($oid, 0, -1) ?: '';
|
||||
}
|
||||
}
|
91
lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/OctetString.php
vendored
Normal file
91
lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/OctetString.php
vendored
Normal file
|
@ -0,0 +1,91 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\ASN1\Universal;
|
||||
|
||||
use Exception;
|
||||
use FG\ASN1\ASNObject;
|
||||
use FG\ASN1\Parsable;
|
||||
use FG\ASN1\Identifier;
|
||||
|
||||
class OctetString extends ASNObject implements Parsable
|
||||
{
|
||||
protected $value;
|
||||
|
||||
public function __construct($value)
|
||||
{
|
||||
if (is_string($value)) {
|
||||
// remove gaps between hex digits
|
||||
$value = preg_replace('/\s|0x/', '', $value);
|
||||
} elseif (is_numeric($value)) {
|
||||
$value = dechex($value);
|
||||
} elseif ($value === null) {
|
||||
return;
|
||||
} else {
|
||||
throw new Exception('OctetString: unrecognized input type!');
|
||||
}
|
||||
|
||||
if (strlen($value) % 2 != 0) {
|
||||
// transform values like 1F2 to 01F2
|
||||
$value = '0'.$value;
|
||||
}
|
||||
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
public function getType()
|
||||
{
|
||||
return Identifier::OCTETSTRING;
|
||||
}
|
||||
|
||||
protected function calculateContentLength()
|
||||
{
|
||||
return strlen($this->value) / 2;
|
||||
}
|
||||
|
||||
protected function getEncodedValue()
|
||||
{
|
||||
$value = $this->value;
|
||||
$result = '';
|
||||
|
||||
//Actual content
|
||||
while (strlen($value) >= 2) {
|
||||
// get the hex value byte by byte from the string and and add it to binary result
|
||||
$result .= chr(hexdec(substr($value, 0, 2)));
|
||||
$value = substr($value, 2);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getContent()
|
||||
{
|
||||
return strtoupper($this->value);
|
||||
}
|
||||
|
||||
public function getBinaryContent()
|
||||
{
|
||||
return $this->getEncodedValue();
|
||||
}
|
||||
|
||||
public static function fromBinary(&$binaryData, &$offsetIndex = 0)
|
||||
{
|
||||
self::parseIdentifier($binaryData[$offsetIndex], Identifier::OCTETSTRING, $offsetIndex++);
|
||||
$contentLength = self::parseContentLength($binaryData, $offsetIndex);
|
||||
|
||||
$value = substr($binaryData, $offsetIndex, $contentLength);
|
||||
$offsetIndex += $contentLength;
|
||||
|
||||
$parsedObject = new self(bin2hex($value));
|
||||
$parsedObject->setContentLength($contentLength);
|
||||
|
||||
return $parsedObject;
|
||||
}
|
||||
}
|
53
lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/PrintableString.php
vendored
Normal file
53
lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/PrintableString.php
vendored
Normal file
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\ASN1\Universal;
|
||||
|
||||
use FG\ASN1\AbstractString;
|
||||
use FG\ASN1\Identifier;
|
||||
|
||||
class PrintableString extends AbstractString
|
||||
{
|
||||
/**
|
||||
* Creates a new ASN.1 PrintableString.
|
||||
*
|
||||
* The ITU-T X.680 Table 8 permits the following characters:
|
||||
* Latin capital letters A,B, ... Z
|
||||
* Latin small letters a,b, ... z
|
||||
* Digits 0,1, ... 9
|
||||
* SPACE (space)
|
||||
* APOSTROPHE '
|
||||
* LEFT PARENTHESIS (
|
||||
* RIGHT PARENTHESIS )
|
||||
* PLUS SIGN +
|
||||
* COMMA ,
|
||||
* HYPHEN-MINUS -
|
||||
* FULL STOP .
|
||||
* SOLIDUS /
|
||||
* COLON :
|
||||
* EQUALS SIGN =
|
||||
* QUESTION MARK ?
|
||||
*
|
||||
* @param string $string
|
||||
*/
|
||||
public function __construct($string)
|
||||
{
|
||||
$this->value = $string;
|
||||
$this->allowNumbers();
|
||||
$this->allowAllLetters();
|
||||
$this->allowSpaces();
|
||||
$this->allowCharacters("'", '(', ')', '+', '-', '.', ',', '/', ':', '=', '?');
|
||||
}
|
||||
|
||||
public function getType()
|
||||
{
|
||||
return Identifier::PRINTABLE_STRING;
|
||||
}
|
||||
}
|
57
lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/RelativeObjectIdentifier.php
vendored
Normal file
57
lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/RelativeObjectIdentifier.php
vendored
Normal file
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\ASN1\Universal;
|
||||
|
||||
use Exception;
|
||||
use FG\ASN1\Parsable;
|
||||
use FG\ASN1\Identifier;
|
||||
use FG\ASN1\Exception\ParserException;
|
||||
|
||||
class RelativeObjectIdentifier extends ObjectIdentifier implements Parsable
|
||||
{
|
||||
public function __construct($subIdentifiers)
|
||||
{
|
||||
$this->value = $subIdentifiers;
|
||||
$this->subIdentifiers = explode('.', $subIdentifiers);
|
||||
$nrOfSubIdentifiers = count($this->subIdentifiers);
|
||||
|
||||
for ($i = 0; $i < $nrOfSubIdentifiers; $i++) {
|
||||
if (is_numeric($this->subIdentifiers[$i])) {
|
||||
// enforce the integer type
|
||||
$this->subIdentifiers[$i] = intval($this->subIdentifiers[$i]);
|
||||
} else {
|
||||
throw new Exception("[{$subIdentifiers}] is no valid object identifier (sub identifier ".($i + 1).' is not numeric)!');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getType()
|
||||
{
|
||||
return Identifier::RELATIVE_OID;
|
||||
}
|
||||
|
||||
public static function fromBinary(&$binaryData, &$offsetIndex = 0)
|
||||
{
|
||||
self::parseIdentifier($binaryData[$offsetIndex], Identifier::RELATIVE_OID, $offsetIndex++);
|
||||
$contentLength = self::parseContentLength($binaryData, $offsetIndex, 1);
|
||||
|
||||
try {
|
||||
$oidString = self::parseOid($binaryData, $offsetIndex, $contentLength);
|
||||
} catch (ParserException $e) {
|
||||
throw new ParserException('Malformed ASN.1 Relative Object Identifier', $e->getOffset());
|
||||
}
|
||||
|
||||
$parsedObject = new self($oidString);
|
||||
$parsedObject->setContentLength($contentLength);
|
||||
|
||||
return $parsedObject;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\ASN1\Universal;
|
||||
|
||||
use FG\ASN1\Construct;
|
||||
use FG\ASN1\Parsable;
|
||||
use FG\ASN1\Identifier;
|
||||
|
||||
class Sequence extends Construct implements Parsable
|
||||
{
|
||||
public function getType()
|
||||
{
|
||||
return Identifier::SEQUENCE;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\ASN1\Universal;
|
||||
|
||||
use FG\ASN1\Identifier;
|
||||
|
||||
class Set extends Sequence
|
||||
{
|
||||
public function getType()
|
||||
{
|
||||
return Identifier::SET;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\ASN1\Universal;
|
||||
|
||||
use FG\ASN1\AbstractString;
|
||||
use FG\ASN1\Identifier;
|
||||
|
||||
class T61String extends AbstractString
|
||||
{
|
||||
/**
|
||||
* Creates a new ASN.1 T61 String.
|
||||
* TODO The encodable characters of this type are not yet checked.
|
||||
*
|
||||
* @see http://en.wikipedia.org/wiki/ITU_T.61
|
||||
*
|
||||
* @param string $string
|
||||
*/
|
||||
public function __construct($string)
|
||||
{
|
||||
$this->value = $string;
|
||||
$this->allowAll();
|
||||
}
|
||||
|
||||
public function getType()
|
||||
{
|
||||
return Identifier::T61_STRING;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\ASN1\Universal;
|
||||
|
||||
use FG\ASN1\AbstractTime;
|
||||
use FG\ASN1\Parsable;
|
||||
use FG\ASN1\Identifier;
|
||||
use FG\ASN1\Exception\ParserException;
|
||||
|
||||
/**
|
||||
* This ASN.1 universal type contains the calendar date and time.
|
||||
*
|
||||
* The precision is one minute or one second and optionally a
|
||||
* local time differential from coordinated universal time.
|
||||
*
|
||||
* Decoding of this type will accept the Basic Encoding Rules (BER)
|
||||
* The encoding will comply with the Distinguished Encoding Rules (DER).
|
||||
*/
|
||||
class UTCTime extends AbstractTime implements Parsable
|
||||
{
|
||||
public function getType()
|
||||
{
|
||||
return Identifier::UTC_TIME;
|
||||
}
|
||||
|
||||
protected function calculateContentLength()
|
||||
{
|
||||
return 13; // Content is a string o the following format: YYMMDDhhmmssZ (13 octets)
|
||||
}
|
||||
|
||||
protected function getEncodedValue()
|
||||
{
|
||||
return $this->value->format('ymdHis').'Z';
|
||||
}
|
||||
|
||||
public static function fromBinary(&$binaryData, &$offsetIndex = 0)
|
||||
{
|
||||
self::parseIdentifier($binaryData[$offsetIndex], Identifier::UTC_TIME, $offsetIndex++);
|
||||
$contentLength = self::parseContentLength($binaryData, $offsetIndex, 11);
|
||||
|
||||
$format = 'ymdGi';
|
||||
$dateTimeString = substr($binaryData, $offsetIndex, 10);
|
||||
$offsetIndex += 10;
|
||||
|
||||
// extract optional seconds part
|
||||
if ($binaryData[$offsetIndex] != 'Z'
|
||||
&& $binaryData[$offsetIndex] != '+'
|
||||
&& $binaryData[$offsetIndex] != '-') {
|
||||
$dateTimeString .= substr($binaryData, $offsetIndex, 2);
|
||||
$offsetIndex += 2;
|
||||
$format .= 's';
|
||||
}
|
||||
|
||||
$dateTime = \DateTime::createFromFormat($format, $dateTimeString, new \DateTimeZone('UTC'));
|
||||
|
||||
// extract time zone settings
|
||||
if ($binaryData[$offsetIndex] == '+'
|
||||
|| $binaryData[$offsetIndex] == '-') {
|
||||
$dateTime = static::extractTimeZoneData($binaryData, $offsetIndex, $dateTime);
|
||||
} elseif ($binaryData[$offsetIndex++] != 'Z') {
|
||||
throw new ParserException('Invalid UTC String', $offsetIndex);
|
||||
}
|
||||
|
||||
$parsedObject = new self($dateTime);
|
||||
$parsedObject->setContentLength($contentLength);
|
||||
|
||||
return $parsedObject;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\ASN1\Universal;
|
||||
|
||||
use FG\ASN1\AbstractString;
|
||||
use FG\ASN1\Identifier;
|
||||
|
||||
class UTF8String extends AbstractString
|
||||
{
|
||||
/**
|
||||
* Creates a new ASN.1 Universal String.
|
||||
* TODO The encodable characters of this type are not yet checked.
|
||||
*
|
||||
* @param string $string
|
||||
*/
|
||||
public function __construct($string)
|
||||
{
|
||||
$this->value = $string;
|
||||
$this->allowAll();
|
||||
}
|
||||
|
||||
public function getType()
|
||||
{
|
||||
return Identifier::UTF8_STRING;
|
||||
}
|
||||
}
|
36
lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/UniversalString.php
vendored
Normal file
36
lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/UniversalString.php
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\ASN1\Universal;
|
||||
|
||||
use FG\ASN1\AbstractString;
|
||||
use FG\ASN1\Identifier;
|
||||
|
||||
class UniversalString extends AbstractString
|
||||
{
|
||||
/**
|
||||
* Creates a new ASN.1 Universal String.
|
||||
* TODO The encodable characters of this type are not yet checked.
|
||||
*
|
||||
* @see http://en.wikipedia.org/wiki/Universal_Character_Set
|
||||
*
|
||||
* @param string $string
|
||||
*/
|
||||
public function __construct($string)
|
||||
{
|
||||
$this->value = $string;
|
||||
$this->allowAll();
|
||||
}
|
||||
|
||||
public function getType()
|
||||
{
|
||||
return Identifier::UNIVERSAL_STRING;
|
||||
}
|
||||
}
|
34
lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/VisibleString.php
vendored
Normal file
34
lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/VisibleString.php
vendored
Normal file
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\ASN1\Universal;
|
||||
|
||||
use FG\ASN1\AbstractString;
|
||||
use FG\ASN1\Identifier;
|
||||
|
||||
class VisibleString extends AbstractString
|
||||
{
|
||||
/**
|
||||
* Creates a new ASN.1 Visible String.
|
||||
* TODO The encodable characters of this type are not yet checked.
|
||||
*
|
||||
* @param string $string
|
||||
*/
|
||||
public function __construct($string)
|
||||
{
|
||||
$this->value = $string;
|
||||
$this->allowAll();
|
||||
}
|
||||
|
||||
public function getType()
|
||||
{
|
||||
return Identifier::VISIBLE_STRING;
|
||||
}
|
||||
}
|
59
lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/UnknownConstructedObject.php
vendored
Normal file
59
lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/UnknownConstructedObject.php
vendored
Normal file
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\ASN1;
|
||||
|
||||
class UnknownConstructedObject extends Construct
|
||||
{
|
||||
private $identifier;
|
||||
private $contentLength;
|
||||
|
||||
/**
|
||||
* @param string $binaryData
|
||||
* @param int $offsetIndex
|
||||
*
|
||||
* @throws \FG\ASN1\Exception\ParserException
|
||||
*/
|
||||
public function __construct($binaryData, &$offsetIndex)
|
||||
{
|
||||
$this->identifier = self::parseBinaryIdentifier($binaryData, $offsetIndex);
|
||||
$this->contentLength = self::parseContentLength($binaryData, $offsetIndex);
|
||||
|
||||
$children = [];
|
||||
$octetsToRead = $this->contentLength;
|
||||
while ($octetsToRead > 0) {
|
||||
$newChild = ASNObject::fromBinary($binaryData, $offsetIndex);
|
||||
$octetsToRead -= $newChild->getObjectLength();
|
||||
$children[] = $newChild;
|
||||
}
|
||||
|
||||
parent::__construct(...$children);
|
||||
}
|
||||
|
||||
public function getType()
|
||||
{
|
||||
return ord($this->identifier);
|
||||
}
|
||||
|
||||
public function getIdentifier()
|
||||
{
|
||||
return $this->identifier;
|
||||
}
|
||||
|
||||
protected function calculateContentLength()
|
||||
{
|
||||
return $this->contentLength;
|
||||
}
|
||||
|
||||
protected function getEncodedValue()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\ASN1;
|
||||
|
||||
class UnknownObject extends ASNObject
|
||||
{
|
||||
/** @var string */
|
||||
private $value;
|
||||
|
||||
private $identifier;
|
||||
|
||||
/**
|
||||
* @param string|int $identifier Either the first identifier octet as int or all identifier bytes as a string
|
||||
* @param int $contentLength
|
||||
*/
|
||||
public function __construct($identifier, $contentLength)
|
||||
{
|
||||
if (is_int($identifier)) {
|
||||
$identifier = chr($identifier);
|
||||
}
|
||||
|
||||
$this->identifier = $identifier;
|
||||
$this->value = "Unparsable Object ({$contentLength} bytes)";
|
||||
$this->setContentLength($contentLength);
|
||||
}
|
||||
|
||||
public function getContent()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
public function getType()
|
||||
{
|
||||
return ord($this->identifier[0]);
|
||||
}
|
||||
|
||||
public function getIdentifier()
|
||||
{
|
||||
return $this->identifier;
|
||||
}
|
||||
|
||||
protected function calculateContentLength()
|
||||
{
|
||||
return $this->getContentLength();
|
||||
}
|
||||
|
||||
protected function getEncodedValue()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,197 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\Utility;
|
||||
|
||||
/**
|
||||
* Class BigInteger
|
||||
* Utility class to remove dependence on a single large number library. Not intended for external use, this class only
|
||||
* implements the functionality needed throughout this project.
|
||||
*
|
||||
* Instances are immutable, all operations return a new instance with the result.
|
||||
*
|
||||
* @package FG\Utility
|
||||
* @internal
|
||||
*/
|
||||
abstract class BigInteger
|
||||
{
|
||||
/**
|
||||
* Force a preference on the underlying big number implementation, useful for testing.
|
||||
* @var string|null
|
||||
*/
|
||||
private static $_prefer;
|
||||
|
||||
public static function setPrefer($prefer = null)
|
||||
{
|
||||
self::$_prefer = $prefer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a BigInteger instance based off the base 10 string or an integer.
|
||||
* @param string|int $val
|
||||
* @return BigInteger
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public static function create($val)
|
||||
{
|
||||
if (self::$_prefer) {
|
||||
switch (self::$_prefer) {
|
||||
case 'gmp':
|
||||
$ret = new BigIntegerGmp();
|
||||
break;
|
||||
case 'bcmath':
|
||||
$ret = new BigIntegerBcmath();
|
||||
break;
|
||||
default:
|
||||
throw new \UnexpectedValueException('Unknown number implementation: ' . self::$_prefer);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// autodetect
|
||||
if (extension_loaded('gmp')) {
|
||||
$ret = new BigIntegerGmp();
|
||||
}
|
||||
elseif (extension_loaded('bcmath')) {
|
||||
$ret = new BigIntegerBcmath();
|
||||
}
|
||||
else {
|
||||
// TODO: potentially offer pure php implementation?
|
||||
throw new \RuntimeException('Requires GMP or bcmath extension.');
|
||||
}
|
||||
}
|
||||
|
||||
if (is_int($val)) {
|
||||
$ret->_fromInteger($val);
|
||||
}
|
||||
else {
|
||||
// convert to string, if not already one
|
||||
$val = (string)$val;
|
||||
|
||||
// validate string
|
||||
if (!preg_match('/^-?[0-9]+$/', $val)) {
|
||||
throw new \InvalidArgumentException('Expects a string representation of an integer.');
|
||||
}
|
||||
$ret->_fromString($val);
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* BigInteger constructor.
|
||||
* Prevent directly instantiating object, use BigInteger::create instead.
|
||||
*/
|
||||
protected function __construct()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses must provide clone functionality.
|
||||
* @return BigInteger
|
||||
*/
|
||||
abstract public function __clone();
|
||||
|
||||
/**
|
||||
* Assign the instance value from base 10 string.
|
||||
* @param string $str
|
||||
*/
|
||||
abstract protected function _fromString($str);
|
||||
|
||||
/**
|
||||
* Assign the instance value from an integer type.
|
||||
* @param int $integer
|
||||
*/
|
||||
abstract protected function _fromInteger($integer);
|
||||
|
||||
/**
|
||||
* Must provide string implementation that returns base 10 number.
|
||||
* @return string
|
||||
*/
|
||||
abstract public function __toString();
|
||||
|
||||
/* INFORMATIONAL FUNCTIONS */
|
||||
|
||||
/**
|
||||
* Return integer, if possible. Throws an exception if the number can not be represented as a native integer.
|
||||
* @return int
|
||||
* @throws \OverflowException
|
||||
*/
|
||||
abstract public function toInteger();
|
||||
|
||||
/**
|
||||
* Is represented integer negative?
|
||||
* @return bool
|
||||
*/
|
||||
abstract public function isNegative();
|
||||
|
||||
/**
|
||||
* Compare the integer with $number, returns a negative integer if $this is less than number, returns 0 if $this is
|
||||
* equal to number and returns a positive integer if $this is greater than number.
|
||||
* @param BigInteger|string|int $number
|
||||
* @return int
|
||||
*/
|
||||
abstract public function compare($number);
|
||||
|
||||
/* MODIFY */
|
||||
|
||||
/**
|
||||
* Add another integer $b and returns the result.
|
||||
* @param BigInteger|string|int $b
|
||||
* @return BigInteger
|
||||
*/
|
||||
abstract public function add($b);
|
||||
|
||||
/**
|
||||
* Subtract $b from $this and returns the result.
|
||||
* @param BigInteger|string|int $b
|
||||
* @return BigInteger
|
||||
*/
|
||||
abstract public function subtract($b);
|
||||
|
||||
/**
|
||||
* Multiply value.
|
||||
* @param BigInteger|string|int $b
|
||||
* @return BigInteger
|
||||
*/
|
||||
abstract public function multiply($b);
|
||||
|
||||
/**
|
||||
* The value $this modulus $b.
|
||||
* @param BigInteger|string|int $b
|
||||
* @return BigInteger
|
||||
*/
|
||||
abstract public function modulus($b);
|
||||
|
||||
/**
|
||||
* Raise $this to the power of $b and returns the result.
|
||||
* @param BigInteger|string|int $b
|
||||
* @return BigInteger
|
||||
*/
|
||||
abstract public function toPower($b);
|
||||
|
||||
/**
|
||||
* Shift the value to the right by a set number of bits and returns the result.
|
||||
* @param int $bits
|
||||
* @return BigInteger
|
||||
*/
|
||||
abstract public function shiftRight($bits = 8);
|
||||
|
||||
/**
|
||||
* Shift the value to the left by a set number of bits and returns the result.
|
||||
* @param int $bits
|
||||
* @return BigInteger
|
||||
*/
|
||||
abstract public function shiftLeft($bits = 8);
|
||||
|
||||
/**
|
||||
* Returns the absolute value.
|
||||
* @return BigInteger
|
||||
*/
|
||||
abstract public function absoluteValue();
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\Utility;
|
||||
|
||||
/**
|
||||
* Class BigIntegerBcmath
|
||||
* Integer representation of big numbers using the bcmath library to perform large operations.
|
||||
* @package FG\Utility
|
||||
* @internal
|
||||
*/
|
||||
class BigIntegerBcmath extends BigInteger
|
||||
{
|
||||
protected $_str;
|
||||
|
||||
public function __clone()
|
||||
{
|
||||
// nothing needed to copy
|
||||
}
|
||||
|
||||
protected function _fromString($str)
|
||||
{
|
||||
$this->_str = (string)$str;
|
||||
}
|
||||
|
||||
protected function _fromInteger($integer)
|
||||
{
|
||||
$this->_str = (string)$integer;
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return $this->_str;
|
||||
}
|
||||
|
||||
public function toInteger()
|
||||
{
|
||||
if ($this->compare(PHP_INT_MAX) > 0 || $this->compare(PHP_INT_MIN) < 0) {
|
||||
throw new \OverflowException(sprintf('Can not represent %s as integer.', $this->_str));
|
||||
}
|
||||
return (int)$this->_str;
|
||||
}
|
||||
|
||||
public function isNegative()
|
||||
{
|
||||
return bccomp($this->_str, '0', 0) < 0;
|
||||
}
|
||||
|
||||
protected function _unwrap($number)
|
||||
{
|
||||
if ($number instanceof self) {
|
||||
return $number->_str;
|
||||
}
|
||||
return $number;
|
||||
}
|
||||
|
||||
public function compare($number)
|
||||
{
|
||||
return bccomp($this->_str, $this->_unwrap($number), 0);
|
||||
}
|
||||
|
||||
public function add($b)
|
||||
{
|
||||
$ret = new self();
|
||||
$ret->_str = bcadd($this->_str, $this->_unwrap($b), 0);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public function subtract($b)
|
||||
{
|
||||
$ret = new self();
|
||||
$ret->_str = bcsub($this->_str, $this->_unwrap($b), 0);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public function multiply($b)
|
||||
{
|
||||
$ret = new self();
|
||||
$ret->_str = bcmul($this->_str, $this->_unwrap($b), 0);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public function modulus($b)
|
||||
{
|
||||
$ret = new self();
|
||||
if ($this->isNegative()) {
|
||||
// bcmod handles negative numbers differently
|
||||
$b = $this->_unwrap($b);
|
||||
$ret->_str = bcsub($b, bcmod(bcsub('0', $this->_str, 0), $b), 0);
|
||||
}
|
||||
else {
|
||||
$ret->_str = bcmod($this->_str, $this->_unwrap($b));
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public function toPower($b)
|
||||
{
|
||||
$ret = new self();
|
||||
$ret->_str = bcpow($this->_str, $this->_unwrap($b), 0);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public function shiftRight($bits = 8)
|
||||
{
|
||||
$ret = new self();
|
||||
$ret->_str = bcdiv($this->_str, bcpow('2', $bits));
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public function shiftLeft($bits = 8) {
|
||||
$ret = new self();
|
||||
$ret->_str = bcmul($this->_str, bcpow('2', $bits));
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public function absoluteValue()
|
||||
{
|
||||
$ret = new self();
|
||||
if (-1 === bccomp($this->_str, '0', 0)) {
|
||||
$ret->_str = bcsub('0', $this->_str, 0);
|
||||
}
|
||||
else {
|
||||
$ret->_str = $this->_str;
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\Utility;
|
||||
|
||||
/**
|
||||
* Class BigIntegerGmp
|
||||
* Integer representation of big numbers using the GMP extension to perform operations.
|
||||
* @package FG\Utility
|
||||
* @internal
|
||||
*/
|
||||
class BigIntegerGmp extends BigInteger
|
||||
{
|
||||
/**
|
||||
* Resource handle.
|
||||
* @var \GMP
|
||||
*/
|
||||
protected $_rh;
|
||||
|
||||
public function __clone()
|
||||
{
|
||||
$this->_rh = gmp_add($this->_rh, 0);
|
||||
}
|
||||
|
||||
protected function _fromString($str)
|
||||
{
|
||||
$this->_rh = gmp_init($str, 10);
|
||||
}
|
||||
|
||||
protected function _fromInteger($integer)
|
||||
{
|
||||
$this->_rh = gmp_init($integer, 10);
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return gmp_strval($this->_rh, 10);
|
||||
}
|
||||
|
||||
public function toInteger()
|
||||
{
|
||||
if ($this->compare(PHP_INT_MAX) > 0 || $this->compare(PHP_INT_MIN) < 0) {
|
||||
throw new \OverflowException(sprintf('Can not represent %s as integer.', $this));
|
||||
}
|
||||
return gmp_intval($this->_rh);
|
||||
}
|
||||
|
||||
public function isNegative()
|
||||
{
|
||||
return gmp_sign($this->_rh) === -1;
|
||||
}
|
||||
|
||||
protected function _unwrap($number)
|
||||
{
|
||||
if ($number instanceof self) {
|
||||
return $number->_rh;
|
||||
}
|
||||
return $number;
|
||||
}
|
||||
|
||||
public function compare($number)
|
||||
{
|
||||
return gmp_cmp($this->_rh, $this->_unwrap($number));
|
||||
}
|
||||
|
||||
public function add($b)
|
||||
{
|
||||
$ret = new self();
|
||||
$ret->_rh = gmp_add($this->_rh, $this->_unwrap($b));
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public function subtract($b)
|
||||
{
|
||||
$ret = new self();
|
||||
$ret->_rh = gmp_sub($this->_rh, $this->_unwrap($b));
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public function multiply($b)
|
||||
{
|
||||
$ret = new self();
|
||||
$ret->_rh = gmp_mul($this->_rh, $this->_unwrap($b));
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public function modulus($b)
|
||||
{
|
||||
$ret = new self();
|
||||
$ret->_rh = gmp_mod($this->_rh, $this->_unwrap($b));
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public function toPower($b)
|
||||
{
|
||||
if ($b instanceof self) {
|
||||
// gmp_pow accepts just an integer
|
||||
if ($b->compare(PHP_INT_MAX) > 0) {
|
||||
throw new \UnexpectedValueException('Unable to raise to power greater than PHP_INT_MAX.');
|
||||
}
|
||||
$b = gmp_intval($b->_rh);
|
||||
}
|
||||
$ret = new self();
|
||||
$ret->_rh = gmp_pow($this->_rh, $b);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public function shiftRight($bits=8)
|
||||
{
|
||||
$ret = new self();
|
||||
$ret->_rh = gmp_div($this->_rh, gmp_pow(2, $bits));
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public function shiftLeft($bits=8)
|
||||
{
|
||||
$ret = new self();
|
||||
$ret->_rh = gmp_mul($this->_rh, gmp_pow(2, $bits));
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public function absoluteValue()
|
||||
{
|
||||
$ret = new self();
|
||||
$ret->_rh = gmp_abs($this->_rh);
|
||||
return $ret;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\X509;
|
||||
|
||||
use FG\ASN1\Universal\NullObject;
|
||||
use FG\ASN1\Composite\AttributeTypeAndValue;
|
||||
|
||||
class AlgorithmIdentifier extends AttributeTypeAndValue
|
||||
{
|
||||
public function __construct($objectIdentifierString)
|
||||
{
|
||||
parent::__construct($objectIdentifierString, new NullObject());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\X509\CSR;
|
||||
|
||||
use FG\ASN1\ASNObject;
|
||||
use FG\X509\CertificateExtensions;
|
||||
use FG\ASN1\OID;
|
||||
use FG\ASN1\Parsable;
|
||||
use FG\ASN1\Construct;
|
||||
use FG\ASN1\Identifier;
|
||||
use FG\ASN1\Universal\Set;
|
||||
use FG\ASN1\Universal\Sequence;
|
||||
use FG\ASN1\Universal\ObjectIdentifier;
|
||||
|
||||
class Attributes extends Construct implements Parsable
|
||||
{
|
||||
public function getType()
|
||||
{
|
||||
return 0xA0;
|
||||
}
|
||||
|
||||
public function addAttribute($objectIdentifier, Set $attribute)
|
||||
{
|
||||
if (is_string($objectIdentifier)) {
|
||||
$objectIdentifier = new ObjectIdentifier($objectIdentifier);
|
||||
}
|
||||
$attributeSequence = new Sequence($objectIdentifier, $attribute);
|
||||
$attributeSequence->getNumberOfLengthOctets(); // length and number of length octets is calculated
|
||||
$this->addChild($attributeSequence);
|
||||
}
|
||||
|
||||
public static function fromBinary(&$binaryData, &$offsetIndex = 0)
|
||||
{
|
||||
self::parseIdentifier($binaryData[$offsetIndex], 0xA0, $offsetIndex++);
|
||||
$contentLength = self::parseContentLength($binaryData, $offsetIndex);
|
||||
$octetsToRead = $contentLength;
|
||||
|
||||
$parsedObject = new self();
|
||||
while ($octetsToRead > 0) {
|
||||
$initialOffset = $offsetIndex; // used to calculate how much bits have been read
|
||||
self::parseIdentifier($binaryData[$offsetIndex], Identifier::SEQUENCE, $offsetIndex++);
|
||||
self::parseContentLength($binaryData, $offsetIndex);
|
||||
|
||||
$objectIdentifier = ObjectIdentifier::fromBinary($binaryData, $offsetIndex);
|
||||
$oidString = $objectIdentifier->getContent();
|
||||
if ($oidString == OID::PKCS9_EXTENSION_REQUEST) {
|
||||
$attribute = CertificateExtensions::fromBinary($binaryData, $offsetIndex);
|
||||
} else {
|
||||
$attribute = ASNObject::fromBinary($binaryData, $offsetIndex);
|
||||
}
|
||||
|
||||
$parsedObject->addAttribute($objectIdentifier, $attribute);
|
||||
$octetsToRead -= ($offsetIndex - $initialOffset);
|
||||
}
|
||||
|
||||
$parsedObject->setContentLength($contentLength);
|
||||
|
||||
return $parsedObject;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\X509\CSR;
|
||||
|
||||
use FG\ASN1\OID;
|
||||
use FG\ASN1\Universal\Integer;
|
||||
use FG\ASN1\Universal\BitString;
|
||||
use FG\ASN1\Universal\Sequence;
|
||||
use FG\X509\CertificateSubject;
|
||||
use FG\X509\AlgorithmIdentifier;
|
||||
use FG\X509\PublicKey;
|
||||
|
||||
class CSR extends Sequence
|
||||
{
|
||||
const CSR_VERSION_NR = 0;
|
||||
|
||||
protected $subject;
|
||||
protected $publicKey;
|
||||
protected $signature;
|
||||
protected $signatureAlgorithm;
|
||||
|
||||
protected $startSequence;
|
||||
|
||||
/**
|
||||
* @param string $commonName
|
||||
* @param string $email
|
||||
* @param string $organization
|
||||
* @param string $locality
|
||||
* @param string $state
|
||||
* @param string $country
|
||||
* @param string $organizationalUnit
|
||||
* @param string $publicKey
|
||||
* @param string $signature
|
||||
* @param string $signatureAlgorithm
|
||||
*/
|
||||
public function __construct($commonName, $email, $organization, $locality, $state, $country, $organizationalUnit, $publicKey, $signature, $signatureAlgorithm = OID::SHA1_WITH_RSA_SIGNATURE)
|
||||
{
|
||||
$this->subject = new CertificateSubject(
|
||||
$commonName,
|
||||
$email,
|
||||
$organization,
|
||||
$locality,
|
||||
$state,
|
||||
$country,
|
||||
$organizationalUnit
|
||||
);
|
||||
$this->publicKey = $publicKey;
|
||||
$this->signature = $signature;
|
||||
$this->signatureAlgorithm = $signatureAlgorithm;
|
||||
|
||||
$this->createCSRSequence();
|
||||
}
|
||||
|
||||
protected function createCSRSequence()
|
||||
{
|
||||
$versionNr = new Integer(self::CSR_VERSION_NR);
|
||||
$publicKey = new PublicKey($this->publicKey);
|
||||
$signature = new BitString($this->signature);
|
||||
$signatureAlgorithm = new AlgorithmIdentifier($this->signatureAlgorithm);
|
||||
|
||||
$certRequestInfo = new Sequence($versionNr, $this->subject, $publicKey);
|
||||
|
||||
$this->addChild($certRequestInfo);
|
||||
$this->addChild($signatureAlgorithm);
|
||||
$this->addChild($signature);
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
$tmp = base64_encode($this->getBinary());
|
||||
|
||||
for ($i = 0; $i < strlen($tmp); $i++) {
|
||||
if (($i + 2) % 65 == 0) {
|
||||
$tmp = substr($tmp, 0, $i + 1)."\n".substr($tmp, $i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
$result = '-----BEGIN CERTIFICATE REQUEST-----'.PHP_EOL;
|
||||
$result .= $tmp.PHP_EOL;
|
||||
$result .= '-----END CERTIFICATE REQUEST-----';
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getVersion()
|
||||
{
|
||||
return self::CSR_VERSION_NR;
|
||||
}
|
||||
|
||||
public function getOrganizationName()
|
||||
{
|
||||
return $this->subject->getOrganization();
|
||||
}
|
||||
|
||||
public function getLocalName()
|
||||
{
|
||||
return $this->subject->getLocality();
|
||||
}
|
||||
|
||||
public function getState()
|
||||
{
|
||||
return $this->subject->getState();
|
||||
}
|
||||
|
||||
public function getCountry()
|
||||
{
|
||||
return $this->subject->getCountry();
|
||||
}
|
||||
|
||||
public function getOrganizationalUnit()
|
||||
{
|
||||
return $this->subject->getOrganizationalUnit();
|
||||
}
|
||||
|
||||
public function getPublicKey()
|
||||
{
|
||||
return $this->publicKey;
|
||||
}
|
||||
|
||||
public function getSignature()
|
||||
{
|
||||
return $this->signature;
|
||||
}
|
||||
|
||||
public function getSignatureAlgorithm()
|
||||
{
|
||||
return $this->signatureAlgorithm;
|
||||
}
|
||||
}
|
100
lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/CertificateExtensions.php
vendored
Normal file
100
lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/CertificateExtensions.php
vendored
Normal file
|
@ -0,0 +1,100 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\X509;
|
||||
|
||||
use FG\ASN1\Exception\ParserException;
|
||||
use FG\ASN1\OID;
|
||||
use FG\ASN1\ASNObject;
|
||||
use FG\ASN1\Parsable;
|
||||
use FG\ASN1\Identifier;
|
||||
use FG\ASN1\Universal\OctetString;
|
||||
use FG\ASN1\Universal\Set;
|
||||
use FG\ASN1\Universal\Sequence;
|
||||
use FG\ASN1\Universal\ObjectIdentifier;
|
||||
use FG\X509\SAN\SubjectAlternativeNames;
|
||||
|
||||
class CertificateExtensions extends Set implements Parsable
|
||||
{
|
||||
private $innerSequence;
|
||||
private $extensions = [];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->innerSequence = new Sequence();
|
||||
parent::__construct($this->innerSequence);
|
||||
}
|
||||
|
||||
public function addSubjectAlternativeNames(SubjectAlternativeNames $sans)
|
||||
{
|
||||
$this->addExtension(OID::CERT_EXT_SUBJECT_ALT_NAME, $sans);
|
||||
}
|
||||
|
||||
private function addExtension($oidString, ASNObject $extension)
|
||||
{
|
||||
$sequence = new Sequence();
|
||||
$sequence->addChild(new ObjectIdentifier($oidString));
|
||||
$sequence->addChild($extension);
|
||||
|
||||
$this->innerSequence->addChild($sequence);
|
||||
$this->extensions[] = $extension;
|
||||
}
|
||||
|
||||
public function getContent()
|
||||
{
|
||||
return $this->extensions;
|
||||
}
|
||||
|
||||
public static function fromBinary(&$binaryData, &$offsetIndex = 0)
|
||||
{
|
||||
self::parseIdentifier($binaryData[$offsetIndex], Identifier::SET, $offsetIndex++);
|
||||
self::parseContentLength($binaryData, $offsetIndex);
|
||||
|
||||
$tmpOffset = $offsetIndex;
|
||||
$extensions = Sequence::fromBinary($binaryData, $offsetIndex);
|
||||
$tmpOffset += 1 + $extensions->getNumberOfLengthOctets();
|
||||
|
||||
$parsedObject = new self();
|
||||
foreach ($extensions as $extension) {
|
||||
if ($extension->getType() != Identifier::SEQUENCE) {
|
||||
//FIXME wrong offset index
|
||||
throw new ParserException('Could not parse Certificate Extensions: Expected ASN.1 Sequence but got '.$extension->getTypeName(), $offsetIndex);
|
||||
}
|
||||
|
||||
$tmpOffset += 1 + $extension->getNumberOfLengthOctets();
|
||||
$children = $extension->getChildren();
|
||||
if (count($children) < 2) {
|
||||
throw new ParserException('Could not parse Certificate Extensions: Needs at least two child elements per extension sequence (object identifier and octet string)', $tmpOffset);
|
||||
}
|
||||
/** @var \FG\ASN1\ASNObject $objectIdentifier */
|
||||
$objectIdentifier = $children[0];
|
||||
|
||||
/** @var OctetString $octetString */
|
||||
$octetString = $children[1];
|
||||
|
||||
if ($objectIdentifier->getType() != Identifier::OBJECT_IDENTIFIER) {
|
||||
throw new ParserException('Could not parse Certificate Extensions: Expected ASN.1 Object Identifier but got '.$extension->getTypeName(), $tmpOffset);
|
||||
}
|
||||
|
||||
$tmpOffset += $objectIdentifier->getObjectLength();
|
||||
|
||||
if ($objectIdentifier->getContent() == OID::CERT_EXT_SUBJECT_ALT_NAME) {
|
||||
$sans = SubjectAlternativeNames::fromBinary($binaryData, $tmpOffset);
|
||||
$parsedObject->addSubjectAlternativeNames($sans);
|
||||
} else {
|
||||
// can now only parse SANs. There might be more in the future
|
||||
$tmpOffset += $octetString->getObjectLength();
|
||||
}
|
||||
}
|
||||
|
||||
$parsedObject->getBinary(); // Determine the number of content octets and object sizes once (just to let the equality unit tests pass :/ )
|
||||
return $parsedObject;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\X509;
|
||||
|
||||
use FG\ASN1\Composite\RelativeDistinguishedName;
|
||||
use FG\ASN1\Identifier;
|
||||
use FG\ASN1\OID;
|
||||
use FG\ASN1\Parsable;
|
||||
use FG\ASN1\Composite\RDNString;
|
||||
use FG\ASN1\Universal\Sequence;
|
||||
|
||||
class CertificateSubject extends Sequence implements Parsable
|
||||
{
|
||||
private $commonName;
|
||||
private $email;
|
||||
private $organization;
|
||||
private $locality;
|
||||
private $state;
|
||||
private $country;
|
||||
private $organizationalUnit;
|
||||
|
||||
/**
|
||||
* @param string $commonName
|
||||
* @param string $email
|
||||
* @param string $organization
|
||||
* @param string $locality
|
||||
* @param string $state
|
||||
* @param string $country
|
||||
* @param string $organizationalUnit
|
||||
*/
|
||||
public function __construct($commonName, $email, $organization, $locality, $state, $country, $organizationalUnit)
|
||||
{
|
||||
parent::__construct(
|
||||
new RDNString(OID::COUNTRY_NAME, $country),
|
||||
new RDNString(OID::STATE_OR_PROVINCE_NAME, $state),
|
||||
new RDNString(OID::LOCALITY_NAME, $locality),
|
||||
new RDNString(OID::ORGANIZATION_NAME, $organization),
|
||||
new RDNString(OID::OU_NAME, $organizationalUnit),
|
||||
new RDNString(OID::COMMON_NAME, $commonName),
|
||||
new RDNString(OID::PKCS9_EMAIL, $email)
|
||||
);
|
||||
|
||||
$this->commonName = $commonName;
|
||||
$this->email = $email;
|
||||
$this->organization = $organization;
|
||||
$this->locality = $locality;
|
||||
$this->state = $state;
|
||||
$this->country = $country;
|
||||
$this->organizationalUnit = $organizationalUnit;
|
||||
}
|
||||
|
||||
public function getCommonName()
|
||||
{
|
||||
return $this->commonName;
|
||||
}
|
||||
|
||||
public function getEmail()
|
||||
{
|
||||
return $this->email;
|
||||
}
|
||||
|
||||
public function getOrganization()
|
||||
{
|
||||
return $this->organization;
|
||||
}
|
||||
|
||||
public function getLocality()
|
||||
{
|
||||
return $this->locality;
|
||||
}
|
||||
|
||||
public function getState()
|
||||
{
|
||||
return $this->state;
|
||||
}
|
||||
|
||||
public function getCountry()
|
||||
{
|
||||
return $this->country;
|
||||
}
|
||||
|
||||
public function getOrganizationalUnit()
|
||||
{
|
||||
return $this->organizationalUnit;
|
||||
}
|
||||
|
||||
public static function fromBinary(&$binaryData, &$offsetIndex = 0)
|
||||
{
|
||||
self::parseIdentifier($binaryData[$offsetIndex], Identifier::SEQUENCE, $offsetIndex++);
|
||||
$contentLength = self::parseContentLength($binaryData, $offsetIndex);
|
||||
|
||||
$names = [];
|
||||
$octetsToRead = $contentLength;
|
||||
while ($octetsToRead > 0) {
|
||||
$relativeDistinguishedName = RelativeDistinguishedName::fromBinary($binaryData, $offsetIndex);
|
||||
$octetsToRead -= $relativeDistinguishedName->getObjectLength();
|
||||
$names[] = $relativeDistinguishedName;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\X509;
|
||||
|
||||
use FG\ASN1\OID;
|
||||
use FG\ASN1\Universal\NullObject;
|
||||
use FG\ASN1\Universal\Sequence;
|
||||
use FG\ASN1\Universal\BitString;
|
||||
use FG\ASN1\Universal\ObjectIdentifier;
|
||||
|
||||
class PrivateKey extends Sequence
|
||||
{
|
||||
/**
|
||||
* @param string $hexKey
|
||||
* @param \FG\ASN1\ASNObject|string $algorithmIdentifierString
|
||||
*/
|
||||
public function __construct($hexKey, $algorithmIdentifierString = OID::RSA_ENCRYPTION)
|
||||
{
|
||||
parent::__construct(
|
||||
new Sequence(
|
||||
new ObjectIdentifier($algorithmIdentifierString),
|
||||
new NullObject()
|
||||
),
|
||||
new BitString($hexKey)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\X509;
|
||||
|
||||
use FG\ASN1\OID;
|
||||
use FG\ASN1\Universal\NullObject;
|
||||
use FG\ASN1\Universal\Sequence;
|
||||
use FG\ASN1\Universal\BitString;
|
||||
use FG\ASN1\Universal\ObjectIdentifier;
|
||||
|
||||
class PublicKey extends Sequence
|
||||
{
|
||||
/**
|
||||
* @param string $hexKey
|
||||
* @param \FG\ASN1\ASNObject|string $algorithmIdentifierString
|
||||
*/
|
||||
public function __construct($hexKey, $algorithmIdentifierString = OID::RSA_ENCRYPTION)
|
||||
{
|
||||
parent::__construct(
|
||||
new Sequence(
|
||||
new ObjectIdentifier($algorithmIdentifierString),
|
||||
new NullObject()
|
||||
),
|
||||
new BitString($hexKey)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\X509\SAN;
|
||||
|
||||
use FG\ASN1\Universal\GeneralString;
|
||||
|
||||
class DNSName extends GeneralString
|
||||
{
|
||||
const IDENTIFIER = 0x82; // not sure yet why this is the identifier used in SAN extensions
|
||||
|
||||
public function __construct($dnsNameString)
|
||||
{
|
||||
parent::__construct($dnsNameString);
|
||||
}
|
||||
|
||||
public function getType()
|
||||
{
|
||||
return self::IDENTIFIER;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of the PHPASN1 library.
|
||||
*
|
||||
* Copyright © Friedrich Große <friedrich.grosse@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FG\X509\SAN;
|
||||
|
||||
use FG\ASN1\ASNObject;
|
||||
use FG\ASN1\Parsable;
|
||||
use FG\ASN1\Exception\ParserException;
|
||||
|
||||
class IPAddress extends ASNObject implements Parsable
|
||||
{
|
||||
const IDENTIFIER = 0x87; // not sure yet why this is the identifier used in SAN extensions
|
||||
|
||||
/** @var string */
|
||||
private $value;
|
||||
|
||||
public function __construct($ipAddressString)
|
||||
{
|
||||
$this->value = $ipAddressString;
|
||||
}
|
||||
|
||||
public function getType()
|
||||
{
|
||||
return self::IDENTIFIER;
|
||||
}
|
||||
|
||||
public function getContent()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
protected function calculateContentLength()
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
|
||||
protected function getEncodedValue()
|
||||
{
|
||||
$ipParts = explode('.', $this->value);
|
||||
$binary = chr($ipParts[0]);
|
||||
$binary .= chr($ipParts[1]);
|
||||
$binary .= chr($ipParts[2]);
|
||||
$binary .= chr($ipParts[3]);
|
||||
|
||||
return $binary;
|
||||
}
|
||||
|
||||
public static function fromBinary(&$binaryData, &$offsetIndex = 0)
|
||||
{
|
||||
self::parseIdentifier($binaryData[$offsetIndex], self::IDENTIFIER, $offsetIndex++);
|
||||
$contentLength = self::parseContentLength($binaryData, $offsetIndex);
|
||||
if ($contentLength != 4) {
|
||||
throw new ParserException("A FG\\X509\SAN\IPAddress should have a content length of 4. Extracted length was {$contentLength}", $offsetIndex);
|
||||
}
|
||||
|
||||
$ipAddressString = ord($binaryData[$offsetIndex++]).'.';
|
||||
$ipAddressString .= ord($binaryData[$offsetIndex++]).'.';
|
||||
$ipAddressString .= ord($binaryData[$offsetIndex++]).'.';
|
||||
$ipAddressString .= ord($binaryData[$offsetIndex++]);
|
||||
|
||||
$parsedObject = new self($ipAddressString);
|
||||
$parsedObject->getObjectLength();
|
||||
|
||||
return $parsedObject;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue