# Extract certificates from provisioned devices

## Extract certificates via API

Extracting keys and certificates through the Guardian API consists of using the Guardian Library to complete the two certificate and key extraction steps.

### **C# example**

```csharp
public static void GetKeyAndCerts()
{
    medcrypt.guardian.InitializeFiles initializeFiles =
        new medcrypt.guardian.InitializeFiles();

    /* read provisioned files into file structure */
    initializeFiles.trustStore =
        File.ReadAllBytes(@"TrustStore.mcts");
    initializeFiles.privateIdentity =
        File.ReadAllBytes(@"PrivateIdentity.mcpi");
    initializeFiles.certifiedProfile =
        File.ReadAllBytes(@"CertifiedProfile.mcp");

    /* customer data about the provisioning system */
    string componentHandle = "my_component_handle";
    string hardwareId = "my_serial_number";
    string serviceName = "my_service_name";

    /* accept input options, or create default */
    medcrypt.guardian.InitializeOptions options =
       new medcrypt.guardian.InitializeOptions();

    /* initialize guardian for configured operations (key and cert)*/
    medcrypt.guardian.Guardian gdn = new medcrypt.guardian.Guardian();

    gdn.Initialize(
        initializeFiles,
        componentHandle,
        hardwareId,
        new medcrypt.guardian.InitializeOptions());

    List<byte[]> certs = null;
    byte[] key = null;

    medcrypt.guardian.IService service = gdn.FindService(serviceName);

    /* get key  */
    key = service.GetCertificateKey(KeyFormat.PKCS8_PEM);

    /* get length of certificate chain, and add all certs to output
        list */
    ulong chainLen = service.GetCertificateChainLength();
    certs = new List<byte[]>();
    for (ulong i = 0; i < chainLen; i++)
    {
        certs.Add(service.GetCertificate(i, CertFormat.PEM));
    }
}
```

### **C++ example**

```cpp
#include "medcrypt/guardian/GuardianSystem.h"
#include "medcrypt/guardian/Utilities/Files/FileHelpers.h"

#define MSG(x) { printf x; printf("\n"); }
#define MSG_INFO(x) { MSG(x); }
#define MSG_ERROR(x) { printf("ERROR: "); MSG(x); }
#define MSG_WARNING(x) { printf("WARNING: "); MSG(x); }
#define ARBITRARY_KEY_SIZE 128
#define ARBITRARY_CERT_SIZE 3 * 1024

bool GetKeyAndCerts()
{
    medcrypt::guardian::Status status;
    medcrypt::guardian::utilities::InitializeFiles in_files;
    std::string in_component_handle = "my_component_handle";
    std::string in_hardware_id = "my_serial_number";
    std::string in_provisioning_profile_folder =
        "/path/to/provisioned/profile/folder/";
    std::string in_service_name = "my_service_name";

    /* initialize provided guardian */
    medcrypt::guardian::Guardian guardian;
    status = guardian.Initialize(
        in_files,
        in_component_handle.c_str(),
        in_hardware_id.c_str(),
        medcrypt::guardian::InitializeOptions());

    /* check and print non OK error code */
    if (EXTRACT_STATUS(status) != medcrypt::guardian::GuardianStatusEnum::OK) {
        MSG_ERROR(("could not initialize guardian [%s]",
            medcrypt::guardian::GuardianStatusEnum::NameOf(
                EXTRACT_STATUS(status)).c_str()));
        return false;
    }

    std::unique_ptr<medcrypt::guardian::Service> service;
    /* find desired service by name */
    status = guardian.FindService(in_service_name.c_str(), &service);

    /* check and print non OK error code */
    if (EXTRACT_STATUS(status) != medcrypt::guardian::GuardianStatusEnum::OK) {
        MSG_ERROR(("could not find service [%s] [%s]",
            in_service_name.c_str(),
            medcrypt::guardian::GuardianStatusEnum::NameOf(
                EXTRACT_STATUS(status)).c_str()));
        return false;
    }

    std::list<std::vector<char>> io_certs;
    std::vector<unsigned char> io_key;

    io_key.assign(ARBITRARY_KEY_SIZE, '\0');
    size_t size = io_key.size();

    /* retrieve pkcs8 encoded key */
    status = service->GetCertificateKey(io_key.data(), &size);
    if (EXTRACT_STATUS(status) != medcrypt::guardian::GuardianStatusEnum::OK) {
        MSG_ERROR(("could not retrieve key [%s]",
            medcrypt::guardian::GuardianStatusEnum::NameOf(
                EXTRACT_STATUS(status)).c_str()));
        return false;
    }
    io_key.resize(size);

    /* retrieve any available certs from the cert chain */
    size_t chain_length = service->GetCertificateChainLength();
    io_certs.clear();
    for (size_t i = 0; i < chain_length; i++) {
        io_certs.emplace_back();
        size = service->GetCertificateSize(i);
        io_certs.back().assign(size, '\0');

        /* retrieve certificate */
        status = service->GetCertificate(
            i,
            io_certs.back().data(),
            &size);

        if (EXTRACT_STATUS(status) != medcrypt::guardian::GuardianStatusEnum::OK) {
            MSG_ERROR(("could not retrieve cert [%u] [%s]",
                (unsigned int)i,
                medcrypt::guardian::GuardianStatusEnum::NameOf(
                    EXTRACT_STATUS(status)).c_str()));
            return false;
        }
    }

    return true;
}
```

###

### C example

```c
#define MAX_GDN_SIZE 15 * 1024 /* increase as necessary, this memory does not have to be on the stack */
#define ARBITRARY_BUF_SIZE 5 * 1024 /* increase as necessary */
#define ARBITRARY_KEY_SIZE 128
#define ARBITRARY_CERT_SIZE 3 * 1024
#define LEAF_CERT_IDX 0

/* Setup example write callback to be used by guardian streams */
static bool sample_callback(mcg_guardian_ostream_t *stream,
                            const uint8_t *buf,
                            size_t count)
{
    size_t i;
    uint8_t *dest = (uint8_t*)stream->state;
    stream->state = dest + count;

    for (i = 0; i < count; i++)
        dest[i] = buf[i];

    return true;
}

static bool get_key_and_certs()
{
    mcg_status status = MCG_STATUS_FAIL;
    mcg_initialize_options_t init_options = {0};
    mcg_initialize_files_t init_files;
    mcg_guardian_istream_t ts, pi, cp;
    size_t cert_chain_path_length = 0;
    size_t cert_chain_length = 0;

    /* create guardian memory region, this memory can come from any source
        but must be a continuous block */
    mcg_memory_t mcg_memory = {NULL, 0, 0};
    uint8_t memory_buffer[MAX_GDN_SIZE] = {0};
    mcg_memory.mem = &memory_buffer[0];
    mcg_memory.size = sizeof(memory_buffer);

    /* customer data about this provisioning system */
    char component_handle[] = "my_component";
    char hardware_id[] = "my_serial_number";
    char service_name[] = "my_service";

    /* read trust store into this buffer, and set in_ts_len to actual size */
    uint8_t in_ts[ARBITRARY_BUF_SIZE] = {0};
    size_t in_ts_len = 1234;

    /* read private identity into this buffer, and set in_pi_len to actual size */
    uint8_t in_pi[ARBITRARY_BUF_SIZE] = {0};
    size_t in_pi_len = 1234;

    /* read certified profile into this buffer, and set in_cp_len to actual size */
    uint8_t in_cp[ARBITRARY_BUF_SIZE] = {0};
    size_t in_cp_len = 1234;

    /* output buffers */
    uint8_t io_key_buf[ARBITRARY_BUF_SIZE] = {0};
    size_t io_key_buf_len = sizeof(io_key_buf);

    uint8_t io_cert_buf[ARBITRARY_BUF_SIZE] = {0};
    size_t io_cert_buf_len = sizeof(io_cert_buf);

    mcg_guardian_ostream_t out_key;
    mcg_guardian_ostream_t out_cert;

    /* Create streams from provided ts/pi/cp byte buffers */
    ts = mcg_istream_from_buffer((const uint8_t*)in_ts, in_ts_len);
    pi = mcg_istream_from_buffer((const uint8_t*)in_pi, in_pi_len);
    cp = mcg_istream_from_buffer((const uint8_t*)in_cp, in_cp_len);

    /* Load streams into mcg_initialize_files_t */
    init_files.trust_store = &ts;
    init_files.private_identity = &pi;
    init_files.certified_profile = &cp;

    status = mcg_gdn_initialize(
        &mcg_memory,
        &init_files,
        component_handle,
        hardware_id,
        &init_options);

    if (status)
    {
        /* Return failure */
        return false;
    }

    /* setup buffer backed key output stream */
    out_key.write_callback = &sample_callback;
    out_key.max_size = io_key_buf_len;
    out_key.bytes_written = 0;
    out_key.state = io_key_buf;

    status = mcg_gdn_write_key(&mcg_memory,
                             service_name,
                             true, /* true = PEM, false = DER */
                             &out_key);
    if (status)
    {
        printf("Failed to write key");
        return false;
    }

    /* setup buffer backed single cert output stream */
    out_cert.write_callback = &sample_callback;
    out_cert.max_size = io_cert_buf_len;
    out_cert.bytes_written = 0;
    out_cert.state = io_cert_buf;

    status = mcg_gdn_write_cert(&mcg_memory,
                        service_name,
                        LEAF_CERT_IDX, /* Note: Only writes a single certificate */
                        true, /* true = PEM, false = DER */
                        &out_cert);

    if (status)
    {
        printf("Failed to write cert");
        return false;
    }

    return true;
}
```

## Extract certificates via command line

This covers how to use a provisioned device to extract pre-arranged keys and certificates from that device's certified profile (CP). Extracting certificates via the command line consists of using the `mcguard_cert_extract` utility to complete the the following certificate and key extraction steps:&#x20;

1. Initialize Guardian with the device's certified profile.
2. Extract key and desired certificates.

* All command line utilities use a working directory approach. During certificate extraction the `mcguard_cert_extract` utility expects to see a `.mcts`, `.mcpip` and `.mcpp` file in the working directory.
* Any argument inside <> brackets should be replaced with the indicated input data (e.g., If the component handle is device1 `<my_component>` , this could be replaced by `device1`).

```bash
# Syntax 
./mcguard_cert_extract --component <my_component> --hardware-id <my_hardwareid> --service <my_service> --key-dir <key_output_dir> --cert-dir <cert_output_dir> <path to provisioned profile>

# Example
./mcguard_cert_extract --component my_device --hardware-id my_device_001 --service my_service --key-dir /home/user/guardian/keys --cert-dir /home/user/guardian/certs /home/user/guardian/provisioned_profile
```
