-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
640 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
<?xml version='1.0' encoding='UTF-8' standalone='no'?> | ||
<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.9.7" xml:lang="en-US"> | ||
<compounddef id="structcryptx__pkcs8__pubkeyinfo" kind="struct" language="C++" prot="public"> | ||
<compoundname>cryptx_pkcs8_pubkeyinfo</compoundname> | ||
<includes refid="cryptx_8h" local="no">cryptx.h</includes> | ||
<innerclass refid="structcryptx__pkcs8__pubkeyinfo_1_1__objectid" prot="public">cryptx_pkcs8_pubkeyinfo::_objectid</innerclass> | ||
<innerclass refid="structcryptx__pkcs8__pubkeyinfo_1_1__publickey" prot="public">cryptx_pkcs8_pubkeyinfo::_publickey</innerclass> | ||
<sectiondef kind="public-attrib"> | ||
<memberdef kind="variable" id="structcryptx__pkcs8__pubkeyinfo_1af21d3c8cda1d420ef3106571cdc9c701" prot="public" static="no" mutable="no"> | ||
<type>struct <ref refid="structcryptx__pkcs8__pubkeyinfo_1_1__objectid" kindref="compound">cryptx_pkcs8_pubkeyinfo::_objectid</ref></type> | ||
<definition>struct cryptx_pkcs8_pubkeyinfo::_objectid cryptx_pkcs8_pubkeyinfo::objectid</definition> | ||
<argsstring></argsstring> | ||
<name>objectid</name> | ||
<qualifiedname>cryptx_pkcs8_pubkeyinfo::objectid</qualifiedname> | ||
<briefdescription> | ||
</briefdescription> | ||
<detaileddescription> | ||
</detaileddescription> | ||
<inbodydescription> | ||
</inbodydescription> | ||
<location file="/Users/acagliano/Library/Mobile Documents/com~apple~CloudDocs/Repositories/toolchain/src/cryptx/cryptx.h" line="581" column="12"/> | ||
</memberdef> | ||
<memberdef kind="variable" id="structcryptx__pkcs8__pubkeyinfo_1ab38e9748d27cd47033be177bbda43997" prot="public" static="no" mutable="no"> | ||
<type>struct <ref refid="structcryptx__pkcs8__pubkeyinfo_1_1__publickey" kindref="compound">cryptx_pkcs8_pubkeyinfo::_publickey</ref></type> | ||
<definition>struct cryptx_pkcs8_pubkeyinfo::_publickey cryptx_pkcs8_pubkeyinfo::publickey</definition> | ||
<argsstring></argsstring> | ||
<name>publickey</name> | ||
<qualifiedname>cryptx_pkcs8_pubkeyinfo::publickey</qualifiedname> | ||
<briefdescription> | ||
</briefdescription> | ||
<detaileddescription> | ||
</detaileddescription> | ||
<inbodydescription> | ||
</inbodydescription> | ||
<location file="/Users/acagliano/Library/Mobile Documents/com~apple~CloudDocs/Repositories/toolchain/src/cryptx/cryptx.h" line="587" column="13"/> | ||
</memberdef> | ||
</sectiondef> | ||
<briefdescription> | ||
<para>Defines a structure for holding imported RSA or ECC public key data. </para> | ||
</briefdescription> | ||
<detaileddescription> | ||
</detaileddescription> | ||
<collaborationgraph> | ||
<node id="1"> | ||
<label>cryptx_pkcs8_pubkeyinfo</label> | ||
<link refid="structcryptx__pkcs8__pubkeyinfo"/> | ||
<childnode refid="2" relation="usage"> | ||
<edgelabel>objectid</edgelabel> | ||
</childnode> | ||
<childnode refid="3" relation="usage"> | ||
<edgelabel>publickey</edgelabel> | ||
</childnode> | ||
</node> | ||
<node id="2"> | ||
<label>cryptx_pkcs8_pubkeyinfo::_objectid</label> | ||
<link refid="structcryptx__pkcs8__pubkeyinfo_1_1__objectid"/> | ||
</node> | ||
<node id="3"> | ||
<label>cryptx_pkcs8_pubkeyinfo::_publickey</label> | ||
<link refid="structcryptx__pkcs8__pubkeyinfo_1_1__publickey"/> | ||
</node> | ||
</collaborationgraph> | ||
<location file="/Users/acagliano/Library/Mobile Documents/com~apple~CloudDocs/Repositories/toolchain/src/cryptx/cryptx.h" line="576" column="1" bodyfile="/Users/acagliano/Library/Mobile Documents/com~apple~CloudDocs/Repositories/toolchain/src/cryptx/cryptx.h" bodystart="576" bodyend="588"/> | ||
<listofallmembers> | ||
<member refid="structcryptx__pkcs8__pubkeyinfo_1af21d3c8cda1d420ef3106571cdc9c701" prot="public" virt="non-virtual"><scope>cryptx_pkcs8_pubkeyinfo</scope><name>objectid</name></member> | ||
<member refid="structcryptx__pkcs8__pubkeyinfo_1ab38e9748d27cd47033be177bbda43997" prot="public" virt="non-virtual"><scope>cryptx_pkcs8_pubkeyinfo</scope><name>publickey</name></member> | ||
</listofallmembers> | ||
</compounddef> | ||
</doxygen> |
50 changes: 50 additions & 0 deletions
50
docs/doxygen/xml/structcryptx__pkcs8__pubkeyinfo_1_1__objectid.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
<?xml version='1.0' encoding='UTF-8' standalone='no'?> | ||
<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.9.7" xml:lang="en-US"> | ||
<compounddef id="structcryptx__pkcs8__pubkeyinfo_1_1__objectid" kind="struct" language="C++" prot="public"> | ||
<compoundname>cryptx_pkcs8_pubkeyinfo::_objectid</compoundname> | ||
<includes refid="cryptx_8h" local="no">cryptx.h</includes> | ||
<sectiondef kind="public-attrib"> | ||
<memberdef kind="variable" id="structcryptx__pkcs8__pubkeyinfo_1_1__objectid_1aafb48ae19e57ac56110b923ed82e655f" prot="public" static="no" mutable="no"> | ||
<type>uint8_t</type> | ||
<definition>uint8_t cryptx_pkcs8_pubkeyinfo::_objectid::data[32]</definition> | ||
<argsstring>[32]</argsstring> | ||
<name>data</name> | ||
<qualifiedname>cryptx_pkcs8_pubkeyinfo::_objectid::data</qualifiedname> | ||
<briefdescription> | ||
</briefdescription> | ||
<detaileddescription> | ||
</detaileddescription> | ||
<inbodydescription> | ||
</inbodydescription> | ||
<location file="/Users/acagliano/Library/Mobile Documents/com~apple~CloudDocs/Repositories/toolchain/src/cryptx/cryptx.h" line="579" column="13" bodyfile="/Users/acagliano/Library/Mobile Documents/com~apple~CloudDocs/Repositories/toolchain/src/cryptx/cryptx.h" bodystart="579" bodyend="-1"/> | ||
</memberdef> | ||
<memberdef kind="variable" id="structcryptx__pkcs8__pubkeyinfo_1_1__objectid_1abb2e9c6eae04f3ee985af1ff83d5455c" prot="public" static="no" mutable="no"> | ||
<type>size_t</type> | ||
<definition>size_t cryptx_pkcs8_pubkeyinfo::_objectid::len</definition> | ||
<argsstring></argsstring> | ||
<name>len</name> | ||
<qualifiedname>cryptx_pkcs8_pubkeyinfo::_objectid::len</qualifiedname> | ||
<briefdescription> | ||
<para>OBJECT IDENTIFIER bytes. </para> | ||
</briefdescription> | ||
<detaileddescription> | ||
</detaileddescription> | ||
<inbodydescription> | ||
</inbodydescription> | ||
<location file="/Users/acagliano/Library/Mobile Documents/com~apple~CloudDocs/Repositories/toolchain/src/cryptx/cryptx.h" line="580" column="12" bodyfile="/Users/acagliano/Library/Mobile Documents/com~apple~CloudDocs/Repositories/toolchain/src/cryptx/cryptx.h" bodystart="580" bodyend="-1"/> | ||
</memberdef> | ||
</sectiondef> | ||
<briefdescription> | ||
<para>Stores root OBJECT IDENTIFIER. </para> | ||
</briefdescription> | ||
<detaileddescription> | ||
<para>This will likely be the type of public key. <linebreak/> | ||
</para> | ||
</detaileddescription> | ||
<location file="/Users/acagliano/Library/Mobile Documents/com~apple~CloudDocs/Repositories/toolchain/src/cryptx/cryptx.h" line="578" column="3" bodyfile="/Users/acagliano/Library/Mobile Documents/com~apple~CloudDocs/Repositories/toolchain/src/cryptx/cryptx.h" bodystart="578" bodyend="581"/> | ||
<listofallmembers> | ||
<member refid="structcryptx__pkcs8__pubkeyinfo_1_1__objectid_1aafb48ae19e57ac56110b923ed82e655f" prot="public" virt="non-virtual"><scope>cryptx_pkcs8_pubkeyinfo::_objectid</scope><name>data</name></member> | ||
<member refid="structcryptx__pkcs8__pubkeyinfo_1_1__objectid_1abb2e9c6eae04f3ee985af1ff83d5455c" prot="public" virt="non-virtual"><scope>cryptx_pkcs8_pubkeyinfo::_objectid</scope><name>len</name></member> | ||
</listofallmembers> | ||
</compounddef> | ||
</doxygen> |
66 changes: 66 additions & 0 deletions
66
docs/doxygen/xml/structcryptx__pkcs8__pubkeyinfo_1_1__publickey.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
<?xml version='1.0' encoding='UTF-8' standalone='no'?> | ||
<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.9.7" xml:lang="en-US"> | ||
<compounddef id="structcryptx__pkcs8__pubkeyinfo_1_1__publickey" kind="struct" language="C++" prot="public"> | ||
<compoundname>cryptx_pkcs8_pubkeyinfo::_publickey</compoundname> | ||
<includes refid="cryptx_8h" local="no">cryptx.h</includes> | ||
<sectiondef kind="public-attrib"> | ||
<memberdef kind="variable" id="structcryptx__pkcs8__pubkeyinfo_1_1__publickey_1ab063e3e50ab4d8738a0a0dedfe1ceb3b" prot="public" static="no" mutable="no"> | ||
<type>uint8_t</type> | ||
<definition>uint8_t cryptx_pkcs8_pubkeyinfo::_publickey::data[257]</definition> | ||
<argsstring>[257]</argsstring> | ||
<name>data</name> | ||
<qualifiedname>cryptx_pkcs8_pubkeyinfo::_publickey::data</qualifiedname> | ||
<briefdescription> | ||
</briefdescription> | ||
<detaileddescription> | ||
</detaileddescription> | ||
<inbodydescription> | ||
</inbodydescription> | ||
<location file="/Users/acagliano/Library/Mobile Documents/com~apple~CloudDocs/Repositories/toolchain/src/cryptx/cryptx.h" line="584" column="13" bodyfile="/Users/acagliano/Library/Mobile Documents/com~apple~CloudDocs/Repositories/toolchain/src/cryptx/cryptx.h" bodystart="584" bodyend="-1"/> | ||
</memberdef> | ||
<memberdef kind="variable" id="structcryptx__pkcs8__pubkeyinfo_1_1__publickey_1a38564efc77984c28226fe6e269106437" prot="public" static="no" mutable="no"> | ||
<type>size_t</type> | ||
<definition>size_t cryptx_pkcs8_pubkeyinfo::_publickey::len</definition> | ||
<argsstring></argsstring> | ||
<name>len</name> | ||
<qualifiedname>cryptx_pkcs8_pubkeyinfo::_publickey::len</qualifiedname> | ||
<briefdescription> | ||
<para>Stores key data (public modulus for RSA or public key for ECC. *<zwj/>/. </para> | ||
</briefdescription> | ||
<detaileddescription> | ||
</detaileddescription> | ||
<inbodydescription> | ||
</inbodydescription> | ||
<location file="/Users/acagliano/Library/Mobile Documents/com~apple~CloudDocs/Repositories/toolchain/src/cryptx/cryptx.h" line="585" column="12" bodyfile="/Users/acagliano/Library/Mobile Documents/com~apple~CloudDocs/Repositories/toolchain/src/cryptx/cryptx.h" bodystart="585" bodyend="-1"/> | ||
</memberdef> | ||
<memberdef kind="variable" id="structcryptx__pkcs8__pubkeyinfo_1_1__publickey_1a9d747359d62ae394b946892f68e8f832" prot="public" static="no" mutable="no"> | ||
<type>uint24_t</type> | ||
<definition>uint24_t cryptx_pkcs8_pubkeyinfo::_publickey::exponent</definition> | ||
<argsstring></argsstring> | ||
<name>exponent</name> | ||
<qualifiedname>cryptx_pkcs8_pubkeyinfo::_publickey::exponent</qualifiedname> | ||
<briefdescription> | ||
<para>Length of public modulus or public key. *<zwj/>/. </para> | ||
</briefdescription> | ||
<detaileddescription> | ||
</detaileddescription> | ||
<inbodydescription> | ||
</inbodydescription> | ||
<location file="/Users/acagliano/Library/Mobile Documents/com~apple~CloudDocs/Repositories/toolchain/src/cryptx/cryptx.h" line="586" column="14" bodyfile="/Users/acagliano/Library/Mobile Documents/com~apple~CloudDocs/Repositories/toolchain/src/cryptx/cryptx.h" bodystart="586" bodyend="-1"/> | ||
</memberdef> | ||
</sectiondef> | ||
<briefdescription> | ||
<para>Stores public key raw data. </para> | ||
</briefdescription> | ||
<detaileddescription> | ||
<para><linebreak/> | ||
</para> | ||
</detaileddescription> | ||
<location file="/Users/acagliano/Library/Mobile Documents/com~apple~CloudDocs/Repositories/toolchain/src/cryptx/cryptx.h" line="583" column="3" bodyfile="/Users/acagliano/Library/Mobile Documents/com~apple~CloudDocs/Repositories/toolchain/src/cryptx/cryptx.h" bodystart="583" bodyend="587"/> | ||
<listofallmembers> | ||
<member refid="structcryptx__pkcs8__pubkeyinfo_1_1__publickey_1ab063e3e50ab4d8738a0a0dedfe1ceb3b" prot="public" virt="non-virtual"><scope>cryptx_pkcs8_pubkeyinfo::_publickey</scope><name>data</name></member> | ||
<member refid="structcryptx__pkcs8__pubkeyinfo_1_1__publickey_1a9d747359d62ae394b946892f68e8f832" prot="public" virt="non-virtual"><scope>cryptx_pkcs8_pubkeyinfo::_publickey</scope><name>exponent</name></member> | ||
<member refid="structcryptx__pkcs8__pubkeyinfo_1_1__publickey_1a38564efc77984c28226fe6e269106437" prot="public" virt="non-virtual"><scope>cryptx_pkcs8_pubkeyinfo::_publickey</scope><name>len</name></member> | ||
</listofallmembers> | ||
</compounddef> | ||
</doxygen> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
.. _pkcs8: | ||
|
||
PKCS#8 | ||
========= | ||
|
||
.. raw:: html | ||
|
||
<p style="background:rgba(176,196,222,.5); padding:10px; font-family:Arial; margin:20px 0;"><span style="font-weight:bold;">Module Functionality</span><br />Provides functions for the import of PKCS#8-encoded public and private keys that can be used with the RSA and EC modules of this library.</p> | ||
|
||
PKCS#8 stands for **Public Key Cryptography Standards** and specification #8 provides general key encoding guidelines for various forms of public and private keys compatible with this library. Because the API of this library tends to work on raw data (rather than on key structures like other libraries do), this module provides a way to deserialize PKCS#8 keyfiles such that you can access components of the key. You can also pass these public and private key structures directly to the TLS implementation (coming soon). | ||
|
||
PKCS#8 typically encodes keydata using the following workflow: | ||
|
||
(1) The components of the key are encoding using ASN.1/DER. | ||
(2) The ASN.1 structure is then encoded using Base64/PEM. | ||
(3) The key data is wrapped in a header/footer banner indicating the type of key. These banners may be: | ||
|
||
.. code-block:: c | ||
-----BEGIN PUBLIC KEY----- | ||
base64-encoded public key | ||
-----END PUBLIC KEY----- | ||
-----BEGIN PRIVATE KEY----- | ||
base64-encoded private key | ||
-----END PRIVATE KEY----- | ||
-----BEGIN ENCRYPTED PRIVATE KEY----- | ||
base64-encoded encrypted private key | ||
-----END ENCRYPTED PRIVATE KEY----- | ||
Structures | ||
_____________ | ||
|
||
.. doxygenstruct:: cryptx_pkcs8_pubkeyinfo | ||
:project: CryptX | ||
:members: _objectid, _publickey | ||
|
||
Response Codes | ||
_______________ | ||
|
||
.. doxygenenum:: pkcs_error_t | ||
:project: CryptX | ||
|
||
Functions | ||
__________ | ||
|
||
.. doxygenfunction:: cryptx_pkcs8_import_publickey | ||
:project: CryptX | ||
|
||
You can import a keyfile and then access its data like so: | ||
|
||
.. code-block:: c | ||
char *fname = "MyKey"; | ||
uint8_t fp; | ||
// load the key from AppVar file | ||
// requires FILEIOC library | ||
if(!(fp = ti_Open(fname, "r"))) return; // failed to open file | ||
uint8_t *pkcs_data = ti_GetDataPtr(fp); | ||
size_t pkcs_len = ti_GetSize(fp); | ||
ti_Close(fp); | ||
pkcs_error_t err; | ||
cryptx_pkcs8_pubkeyinfo key; | ||
err = cryptx_pkcs8_import_publickey(pkcs_data, pkcs_len, &key); | ||
if(err) return; | ||
key.objectid.data; // pointer to object id | ||
key.objectid.len; // length of object id | ||
key.publickey.data; // pointer to key data (RSA public modulus or ECC pubkey) | ||
key.publickey.len; // pointer to length of key data | ||
key.publickey.exponent; // public exponent for RSA, unused for ECC | ||
Object Identifier Reference | ||
___________________________ | ||
|
||
This section lists algorithm object identifiers supported by this library. Developers should generally never need to use these as the library should handle it internally, but if you need them for other projects or even for custom implementations, here they are. | ||
|
||
**Bear in mind that while this module can successfully import "objects" for most algorithm types, only the ones listed below can actually be USED by the library.** | ||
|
||
+---------------+--------------------------+---------------------------------------+ | ||
| Algorithm | Object Identifier | Bytes | | ||
+===============+==========================+=======================================+ | ||
| RSA | 1.2.840.113549.1.1.1 | $2A,$86,$48,$86,$F7,$0D,$01,$01,$01 | | ||
+---------------+--------------------------+---------------------------------------+ | ||
| EC_SECT233K1 | 1.3.132.0.26 | ?? | | ||
+---------------+--------------------------+---------------------------------------+ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
.. _pkcs8: | ||
|
||
PKCS#8 | ||
========= | ||
|
||
.. raw:: html | ||
|
||
<p style="background:rgba(176,196,222,.5); padding:10px; font-family:Arial; margin:20px 0;"><span style="font-weight:bold;">Module Functionality</span><br />Provides functions for the import of PKCS#8-encoded public and private keys that can be used with the RSA and EC modules of this library.</p> | ||
|
||
PKCS#8 stands for **Public Key Cryptography Standards** and specification #8 provides general key encoding guidelines for various forms of public and private keys compatible with this library. Because the API of this library tends to work on raw data (rather than on key structures like other libraries do), this module provides a way to deserialize PKCS#8 keyfiles such that you can access components of the key. You can also pass these public and private key structures directly to the TLS implementation (coming soon). | ||
|
||
PKCS#8 typically encodes keydata using the following workflow: | ||
|
||
(1) The components of the key are encoding using ASN.1/DER. | ||
(2) The ASN.1 structure is then encoded using Base64/PEM. | ||
(3) The key data is wrapped in a header/footer banner indicating the type of key. These banners may be: | ||
|
||
.. code-block:: c | ||
-----BEGIN PUBLIC KEY----- | ||
base64-encoded public key | ||
-----END PUBLIC KEY----- | ||
-----BEGIN PRIVATE KEY----- | ||
base64-encoded private key | ||
-----END PRIVATE KEY----- | ||
-----BEGIN ENCRYPTED PRIVATE KEY----- | ||
base64-encoded encrypted private key | ||
-----END ENCRYPTED PRIVATE KEY----- | ||
Structures | ||
_____________ | ||
|
||
.. doxygenstruct:: cryptx_pkcs8_pubkeyinfo | ||
:project: CryptX | ||
:members: _objectid, _publickey | ||
|
||
Response Codes | ||
_______________ | ||
|
||
.. doxygenenum:: pkcs_error_t | ||
:project: CryptX | ||
|
||
Functions | ||
__________ | ||
|
||
.. doxygenfunction:: cryptx_pkcs8_import_publickey | ||
:project: CryptX | ||
|
||
You can import a keyfile and then access its data like so: | ||
|
||
.. code-block:: c | ||
char *fname = "MyKey"; | ||
uint8_t fp; | ||
// load the key from AppVar file | ||
// requires FILEIOC library | ||
if(!(fp = ti_Open(fname, "r"))) return; // failed to open file | ||
uint8_t *pkcs_data = ti_GetDataPtr(fp); | ||
size_t pkcs_len = ti_GetSize(fp); | ||
ti_Close(fp); | ||
pkcs_error_t err; | ||
cryptx_pkcs8_pubkeyinfo key; | ||
err = cryptx_pkcs8_import_publickey(pkcs_data, pkcs_len, &key); | ||
if(err) return; | ||
key.objectid.data; // pointer to object id | ||
key.objectid.len; // length of object id | ||
key.publickey.data; // pointer to key data (RSA public modulus or ECC pubkey) | ||
key.publickey.len; // pointer to length of key data | ||
key.publickey.exponent; // public exponent for RSA, unused for ECC | ||
Object Identifier Reference | ||
___________________________ | ||
|
||
This section lists algorithm object identifiers supported by this library. Developers should generally never need to use these as the library should handle it internally, but if you need them for other projects or even for custom implementations, here they are. | ||
|
||
**Bear in mind that while this module can successfully import "objects" for most algorithm types, only the ones listed below can actually be USED by the library.** | ||
|
||
+---------------+--------------------------+---------------------------------------+ | ||
| Algorithm | Object Identifier | Bytes | | ||
+===============+==========================+=======================================+ | ||
| RSA | 1.2.840.113549.1.1.1 | $2A,$86,$48,$86,$F7,$0D,$01,$01,$01 | | ||
+---------------+--------------------------+---------------------------------------+ | ||
| EC_SECT233K1 | 1.3.132.0.26 | ?? | | ||
+---------------+--------------------------+---------------------------------------+ |
Oops, something went wrong.