Home | History | Annotate | Download | only in keymaster
      1 /*
      2  * Copyright 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <keymaster/android_keymaster_messages.h>
     18 #include <keymaster/android_keymaster_utils.h>
     19 
     20 namespace keymaster {
     21 
     22 /*
     23  * Helper functions for working with key blobs.
     24  */
     25 
     26 static void set_key_blob(keymaster_key_blob_t* key_blob, const void* key_material, size_t length) {
     27     delete[] key_blob->key_material;
     28     key_blob->key_material = dup_buffer(key_material, length);
     29     key_blob->key_material_size = length;
     30 }
     31 
     32 static size_t key_blob_size(const keymaster_key_blob_t& key_blob) {
     33     return sizeof(uint32_t) /* key size */ + key_blob.key_material_size;
     34 }
     35 
     36 static uint8_t* serialize_key_blob(const keymaster_key_blob_t& key_blob, uint8_t* buf,
     37                                    const uint8_t* end) {
     38     return append_size_and_data_to_buf(buf, end, key_blob.key_material, key_blob.key_material_size);
     39 }
     40 
     41 static bool deserialize_key_blob(keymaster_key_blob_t* key_blob, const uint8_t** buf_ptr,
     42                                  const uint8_t* end) {
     43     delete[] key_blob->key_material;
     44     key_blob->key_material = 0;
     45     UniquePtr<uint8_t[]> deserialized_key_material;
     46     if (!copy_size_and_data_from_buf(buf_ptr, end, &key_blob->key_material_size,
     47                                      &deserialized_key_material))
     48         return false;
     49     key_blob->key_material = deserialized_key_material.release();
     50     return true;
     51 }
     52 
     53 size_t KeymasterResponse::SerializedSize() const {
     54     if (error != KM_ERROR_OK)
     55         return sizeof(int32_t);
     56     else
     57         return sizeof(int32_t) + NonErrorSerializedSize();
     58 }
     59 
     60 uint8_t* KeymasterResponse::Serialize(uint8_t* buf, const uint8_t* end) const {
     61     buf = append_uint32_to_buf(buf, end, static_cast<uint32_t>(error));
     62     if (error == KM_ERROR_OK)
     63         buf = NonErrorSerialize(buf, end);
     64     return buf;
     65 }
     66 
     67 bool KeymasterResponse::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
     68     if (!copy_uint32_from_buf(buf_ptr, end, &error))
     69         return false;
     70     if (error != KM_ERROR_OK)
     71         return true;
     72     return NonErrorDeserialize(buf_ptr, end);
     73 }
     74 
     75 GenerateKeyResponse::~GenerateKeyResponse() {
     76     delete[] key_blob.key_material;
     77 }
     78 
     79 size_t GenerateKeyResponse::NonErrorSerializedSize() const {
     80     return key_blob_size(key_blob) + enforced.SerializedSize() + unenforced.SerializedSize();
     81 }
     82 
     83 uint8_t* GenerateKeyResponse::NonErrorSerialize(uint8_t* buf, const uint8_t* end) const {
     84     buf = serialize_key_blob(key_blob, buf, end);
     85     buf = enforced.Serialize(buf, end);
     86     return unenforced.Serialize(buf, end);
     87 }
     88 
     89 bool GenerateKeyResponse::NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) {
     90     return deserialize_key_blob(&key_blob, buf_ptr, end) && enforced.Deserialize(buf_ptr, end) &&
     91            unenforced.Deserialize(buf_ptr, end);
     92 }
     93 
     94 GetKeyCharacteristicsRequest::~GetKeyCharacteristicsRequest() {
     95     delete[] key_blob.key_material;
     96 }
     97 
     98 void GetKeyCharacteristicsRequest::SetKeyMaterial(const void* key_material, size_t length) {
     99     set_key_blob(&key_blob, key_material, length);
    100 }
    101 
    102 size_t GetKeyCharacteristicsRequest::SerializedSize() const {
    103     return key_blob_size(key_blob) + additional_params.SerializedSize();
    104 }
    105 
    106 uint8_t* GetKeyCharacteristicsRequest::Serialize(uint8_t* buf, const uint8_t* end) const {
    107     buf = serialize_key_blob(key_blob, buf, end);
    108     return additional_params.Serialize(buf, end);
    109 }
    110 
    111 bool GetKeyCharacteristicsRequest::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
    112     return deserialize_key_blob(&key_blob, buf_ptr, end) &&
    113            additional_params.Deserialize(buf_ptr, end);
    114 }
    115 
    116 size_t GetKeyCharacteristicsResponse::NonErrorSerializedSize() const {
    117     return enforced.SerializedSize() + unenforced.SerializedSize();
    118 }
    119 
    120 uint8_t* GetKeyCharacteristicsResponse::NonErrorSerialize(uint8_t* buf, const uint8_t* end) const {
    121     buf = enforced.Serialize(buf, end);
    122     return unenforced.Serialize(buf, end);
    123 }
    124 
    125 bool GetKeyCharacteristicsResponse::NonErrorDeserialize(const uint8_t** buf_ptr,
    126                                                         const uint8_t* end) {
    127     return enforced.Deserialize(buf_ptr, end) && unenforced.Deserialize(buf_ptr, end);
    128 }
    129 
    130 void BeginOperationRequest::SetKeyMaterial(const void* key_material, size_t length) {
    131     set_key_blob(&key_blob, key_material, length);
    132 }
    133 
    134 size_t BeginOperationRequest::SerializedSize() const {
    135     return sizeof(uint32_t) /* purpose */ + key_blob_size(key_blob) +
    136            additional_params.SerializedSize();
    137 }
    138 
    139 uint8_t* BeginOperationRequest::Serialize(uint8_t* buf, const uint8_t* end) const {
    140     buf = append_uint32_to_buf(buf, end, purpose);
    141     buf = serialize_key_blob(key_blob, buf, end);
    142     return additional_params.Serialize(buf, end);
    143 }
    144 
    145 bool BeginOperationRequest::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
    146     return copy_uint32_from_buf(buf_ptr, end, &purpose) &&
    147            deserialize_key_blob(&key_blob, buf_ptr, end) &&
    148            additional_params.Deserialize(buf_ptr, end);
    149 }
    150 
    151 size_t BeginOperationResponse::NonErrorSerializedSize() const {
    152     if (message_version == 0)
    153         return sizeof(op_handle);
    154     else
    155         return sizeof(op_handle) + output_params.SerializedSize();
    156 }
    157 
    158 uint8_t* BeginOperationResponse::NonErrorSerialize(uint8_t* buf, const uint8_t* end) const {
    159     buf = append_uint64_to_buf(buf, end, op_handle);
    160     if (message_version > 0)
    161         buf = output_params.Serialize(buf, end);
    162     return buf;
    163 }
    164 
    165 bool BeginOperationResponse::NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) {
    166     bool retval = copy_uint64_from_buf(buf_ptr, end, &op_handle);
    167     if (retval && message_version > 0)
    168         retval = output_params.Deserialize(buf_ptr, end);
    169     return retval;
    170 }
    171 
    172 size_t UpdateOperationRequest::SerializedSize() const {
    173     if (message_version == 0)
    174         return sizeof(op_handle) + input.SerializedSize();
    175     else
    176         return sizeof(op_handle) + input.SerializedSize() + additional_params.SerializedSize();
    177 }
    178 
    179 uint8_t* UpdateOperationRequest::Serialize(uint8_t* buf, const uint8_t* end) const {
    180     buf = append_uint64_to_buf(buf, end, op_handle);
    181     buf = input.Serialize(buf, end);
    182     if (message_version > 0)
    183         buf = additional_params.Serialize(buf, end);
    184     return buf;
    185 }
    186 
    187 bool UpdateOperationRequest::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
    188     bool retval = copy_uint64_from_buf(buf_ptr, end, &op_handle) && input.Deserialize(buf_ptr, end);
    189     if (retval && message_version > 0)
    190         retval = additional_params.Deserialize(buf_ptr, end);
    191     return retval;
    192 }
    193 
    194 size_t UpdateOperationResponse::NonErrorSerializedSize() const {
    195     size_t size = 0;
    196     switch (message_version) {
    197     case 3:
    198     case 2:
    199         size += output_params.SerializedSize();
    200         ; /* falls through */
    201     case 1:
    202         size += sizeof(uint32_t);
    203         ; /* falls through */
    204     case 0:
    205         size += output.SerializedSize();
    206         break;
    207 
    208     default:
    209         assert(false);
    210     }
    211 
    212     return size;
    213 }
    214 
    215 uint8_t* UpdateOperationResponse::NonErrorSerialize(uint8_t* buf, const uint8_t* end) const {
    216     buf = output.Serialize(buf, end);
    217     if (message_version > 0)
    218         buf = append_uint32_to_buf(buf, end, input_consumed);
    219     if (message_version > 1)
    220         buf = output_params.Serialize(buf, end);
    221     return buf;
    222 }
    223 
    224 bool UpdateOperationResponse::NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) {
    225     bool retval = output.Deserialize(buf_ptr, end);
    226     if (retval && message_version > 0)
    227         retval = copy_uint32_from_buf(buf_ptr, end, &input_consumed);
    228     if (retval && message_version > 1)
    229         retval = output_params.Deserialize(buf_ptr, end);
    230     return retval;
    231 }
    232 
    233 size_t FinishOperationRequest::SerializedSize() const {
    234     size_t size = 0;
    235     switch (message_version) {
    236     case 3:
    237         size += input.SerializedSize();
    238         ; /* falls through */
    239     case 2:
    240     case 1:
    241         size += additional_params.SerializedSize();
    242         ; /* falls through */
    243     case 0:
    244         size += sizeof(op_handle) + signature.SerializedSize();
    245         break;
    246 
    247     default:
    248         assert(false);  // Should never get here.
    249     }
    250 
    251     return size;
    252 }
    253 
    254 uint8_t* FinishOperationRequest::Serialize(uint8_t* buf, const uint8_t* end) const {
    255     buf = append_uint64_to_buf(buf, end, op_handle);
    256     buf = signature.Serialize(buf, end);
    257     if (message_version > 0)
    258         buf = additional_params.Serialize(buf, end);
    259     if (message_version > 2)
    260         buf = input.Serialize(buf, end);
    261     return buf;
    262 }
    263 
    264 bool FinishOperationRequest::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
    265     bool retval =
    266         copy_uint64_from_buf(buf_ptr, end, &op_handle) && signature.Deserialize(buf_ptr, end);
    267     if (retval && message_version > 0)
    268         retval = additional_params.Deserialize(buf_ptr, end);
    269     if (retval && message_version > 2)
    270         retval = input.Deserialize(buf_ptr, end);
    271     return retval;
    272 }
    273 
    274 size_t FinishOperationResponse::NonErrorSerializedSize() const {
    275     if (message_version < 2)
    276         return output.SerializedSize();
    277     else
    278         return output.SerializedSize() + output_params.SerializedSize();
    279 }
    280 
    281 uint8_t* FinishOperationResponse::NonErrorSerialize(uint8_t* buf, const uint8_t* end) const {
    282     buf = output.Serialize(buf, end);
    283     if (message_version > 1)
    284         buf = output_params.Serialize(buf, end);
    285     return buf;
    286 }
    287 
    288 bool FinishOperationResponse::NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) {
    289     bool retval = output.Deserialize(buf_ptr, end);
    290     if (retval && message_version > 1)
    291         retval = output_params.Deserialize(buf_ptr, end);
    292     return retval;
    293 }
    294 
    295 size_t AddEntropyRequest::SerializedSize() const {
    296     return random_data.SerializedSize();
    297 }
    298 
    299 uint8_t* AddEntropyRequest::Serialize(uint8_t* buf, const uint8_t* end) const {
    300     return random_data.Serialize(buf, end);
    301 }
    302 
    303 bool AddEntropyRequest::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
    304     return random_data.Deserialize(buf_ptr, end);
    305 }
    306 
    307 void ImportKeyRequest::SetKeyMaterial(const void* key_material, size_t length) {
    308     delete[] key_data;
    309     key_data = dup_buffer(key_material, length);
    310     key_data_length = length;
    311 }
    312 
    313 size_t ImportKeyRequest::SerializedSize() const {
    314     return key_description.SerializedSize() + sizeof(uint32_t) /* key_format */ +
    315            sizeof(uint32_t) /* key_data_length */ + key_data_length;
    316 }
    317 
    318 uint8_t* ImportKeyRequest::Serialize(uint8_t* buf, const uint8_t* end) const {
    319     buf = key_description.Serialize(buf, end);
    320     buf = append_uint32_to_buf(buf, end, key_format);
    321     return append_size_and_data_to_buf(buf, end, key_data, key_data_length);
    322 }
    323 
    324 bool ImportKeyRequest::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
    325     delete[] key_data;
    326     key_data = NULL;
    327     UniquePtr<uint8_t[]> deserialized_key_material;
    328     if (!key_description.Deserialize(buf_ptr, end) ||
    329         !copy_uint32_from_buf(buf_ptr, end, &key_format) ||
    330         !copy_size_and_data_from_buf(buf_ptr, end, &key_data_length, &deserialized_key_material))
    331         return false;
    332     key_data = deserialized_key_material.release();
    333     return true;
    334 }
    335 
    336 void ImportKeyResponse::SetKeyMaterial(const void* key_material, size_t length) {
    337     set_key_blob(&key_blob, key_material, length);
    338 }
    339 
    340 size_t ImportKeyResponse::NonErrorSerializedSize() const {
    341     return key_blob_size(key_blob) + enforced.SerializedSize() + unenforced.SerializedSize();
    342 }
    343 
    344 uint8_t* ImportKeyResponse::NonErrorSerialize(uint8_t* buf, const uint8_t* end) const {
    345     buf = serialize_key_blob(key_blob, buf, end);
    346     buf = enforced.Serialize(buf, end);
    347     return unenforced.Serialize(buf, end);
    348 }
    349 
    350 bool ImportKeyResponse::NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) {
    351     return deserialize_key_blob(&key_blob, buf_ptr, end) && enforced.Deserialize(buf_ptr, end) &&
    352            unenforced.Deserialize(buf_ptr, end);
    353 }
    354 
    355 void ExportKeyRequest::SetKeyMaterial(const void* key_material, size_t length) {
    356     set_key_blob(&key_blob, key_material, length);
    357 }
    358 
    359 size_t ExportKeyRequest::SerializedSize() const {
    360     return additional_params.SerializedSize() + sizeof(uint32_t) /* key_format */ +
    361            key_blob_size(key_blob);
    362 }
    363 
    364 uint8_t* ExportKeyRequest::Serialize(uint8_t* buf, const uint8_t* end) const {
    365     buf = additional_params.Serialize(buf, end);
    366     buf = append_uint32_to_buf(buf, end, key_format);
    367     return serialize_key_blob(key_blob, buf, end);
    368 }
    369 
    370 bool ExportKeyRequest::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
    371     return additional_params.Deserialize(buf_ptr, end) &&
    372            copy_uint32_from_buf(buf_ptr, end, &key_format) &&
    373            deserialize_key_blob(&key_blob, buf_ptr, end);
    374 }
    375 
    376 void ExportKeyResponse::SetKeyMaterial(const void* key_material, size_t length) {
    377     delete[] key_data;
    378     key_data = dup_buffer(key_material, length);
    379     key_data_length = length;
    380 }
    381 
    382 size_t ExportKeyResponse::NonErrorSerializedSize() const {
    383     return sizeof(uint32_t) /* key_data_length */ + key_data_length;
    384 }
    385 
    386 uint8_t* ExportKeyResponse::NonErrorSerialize(uint8_t* buf, const uint8_t* end) const {
    387     return append_size_and_data_to_buf(buf, end, key_data, key_data_length);
    388 }
    389 
    390 bool ExportKeyResponse::NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) {
    391     delete[] key_data;
    392     key_data = NULL;
    393     UniquePtr<uint8_t[]> deserialized_key_material;
    394     if (!copy_size_and_data_from_buf(buf_ptr, end, &key_data_length, &deserialized_key_material))
    395         return false;
    396     key_data = deserialized_key_material.release();
    397     return true;
    398 }
    399 
    400 void DeleteKeyRequest::SetKeyMaterial(const void* key_material, size_t length) {
    401     set_key_blob(&key_blob, key_material, length);
    402 }
    403 
    404 size_t DeleteKeyRequest::SerializedSize() const {
    405     return key_blob_size(key_blob);
    406 }
    407 
    408 uint8_t* DeleteKeyRequest::Serialize(uint8_t* buf, const uint8_t* end) const {
    409     return serialize_key_blob(key_blob, buf, end);
    410 }
    411 
    412 bool DeleteKeyRequest::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
    413     return deserialize_key_blob(&key_blob, buf_ptr, end);
    414 }
    415 
    416 size_t GetVersionResponse::NonErrorSerializedSize() const {
    417     return sizeof(major_ver) + sizeof(minor_ver) + sizeof(subminor_ver);
    418 }
    419 
    420 uint8_t* GetVersionResponse::NonErrorSerialize(uint8_t* buf, const uint8_t* end) const {
    421     if (buf + NonErrorSerializedSize() <= end) {
    422         *buf++ = major_ver;
    423         *buf++ = minor_ver;
    424         *buf++ = subminor_ver;
    425     } else {
    426         buf += NonErrorSerializedSize();
    427     }
    428     return buf;
    429 }
    430 
    431 bool GetVersionResponse::NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) {
    432     if (*buf_ptr + NonErrorSerializedSize() > end)
    433         return false;
    434     const uint8_t* tmp = *buf_ptr;
    435     major_ver = *tmp++;
    436     minor_ver = *tmp++;
    437     subminor_ver = *tmp++;
    438     *buf_ptr = tmp;
    439     return true;
    440 }
    441 
    442 AttestKeyRequest::~AttestKeyRequest() {
    443     delete[] key_blob.key_material;
    444 }
    445 
    446 void AttestKeyRequest::SetKeyMaterial(const void* key_material, size_t length) {
    447     set_key_blob(&key_blob, key_material, length);
    448 }
    449 
    450 size_t AttestKeyRequest::SerializedSize() const {
    451     return key_blob_size(key_blob) + attest_params.SerializedSize();
    452 }
    453 
    454 uint8_t* AttestKeyRequest::Serialize(uint8_t* buf, const uint8_t* end) const {
    455     buf = serialize_key_blob(key_blob, buf, end);
    456     return attest_params.Serialize(buf, end);
    457 }
    458 
    459 bool AttestKeyRequest::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
    460     return deserialize_key_blob(&key_blob, buf_ptr, end) && attest_params.Deserialize(buf_ptr, end);
    461 }
    462 
    463 AttestKeyResponse::~AttestKeyResponse() {
    464     for (size_t i = 0; i < certificate_chain.entry_count; ++i)
    465         delete[] certificate_chain.entries[i].data;
    466     delete[] certificate_chain.entries;
    467 }
    468 
    469 const size_t kMaxChainEntryCount = 10;
    470 bool AttestKeyResponse::AllocateChain(size_t entry_count) {
    471     if (entry_count > kMaxChainEntryCount)
    472         return false;
    473 
    474     if (certificate_chain.entries) {
    475         for (size_t i = 0; i < certificate_chain.entry_count; ++i)
    476             delete[] certificate_chain.entries[i].data;
    477         delete[] certificate_chain.entries;
    478     }
    479 
    480     certificate_chain.entry_count = entry_count;
    481     certificate_chain.entries = new keymaster_blob_t[entry_count];
    482     if (!certificate_chain.entries) {
    483         certificate_chain.entry_count = 0;
    484         return false;
    485     }
    486 
    487     memset(certificate_chain.entries, 0, sizeof(certificate_chain.entries[0]) * entry_count);
    488     return true;
    489 }
    490 
    491 size_t AttestKeyResponse::NonErrorSerializedSize() const {
    492     size_t result = sizeof(uint32_t); /* certificate_chain.entry_count */
    493     for (size_t i = 0; i < certificate_chain.entry_count; ++i) {
    494         result += sizeof(uint32_t); /* certificate_chain.entries[i].data_length */
    495         result += certificate_chain.entries[i].data_length;
    496     }
    497     return result;
    498 }
    499 
    500 uint8_t* AttestKeyResponse::NonErrorSerialize(uint8_t* buf, const uint8_t* end) const {
    501     buf = append_uint32_to_buf(buf, end, certificate_chain.entry_count);
    502     for (size_t i = 0; i < certificate_chain.entry_count; ++i) {
    503         buf = append_size_and_data_to_buf(buf, end, certificate_chain.entries[i].data,
    504                                           certificate_chain.entries[i].data_length);
    505     }
    506     return buf;
    507 }
    508 
    509 bool AttestKeyResponse::NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) {
    510     size_t entry_count;
    511     if (!copy_uint32_from_buf(buf_ptr, end, &entry_count) || !AllocateChain(entry_count))
    512         return false;
    513 
    514     for (size_t i = 0; i < certificate_chain.entry_count; ++i) {
    515         UniquePtr<uint8_t[]> data;
    516         size_t data_length;
    517         if (!copy_size_and_data_from_buf(buf_ptr, end, &data_length, &data))
    518             return false;
    519         certificate_chain.entries[i].data = data.release();
    520         certificate_chain.entries[i].data_length = data_length;
    521     }
    522 
    523     return true;
    524 }
    525 
    526 UpgradeKeyRequest::~UpgradeKeyRequest() {
    527     delete[] key_blob.key_material;
    528 }
    529 
    530 void UpgradeKeyRequest::SetKeyMaterial(const void* key_material, size_t length) {
    531     set_key_blob(&key_blob, key_material, length);
    532 }
    533 
    534 size_t UpgradeKeyRequest::SerializedSize() const {
    535     return key_blob_size(key_blob) + upgrade_params.SerializedSize();
    536 }
    537 
    538 uint8_t* UpgradeKeyRequest::Serialize(uint8_t* buf, const uint8_t* end) const {
    539     buf = serialize_key_blob(key_blob, buf, end);
    540     return upgrade_params.Serialize(buf, end);
    541 }
    542 
    543 bool UpgradeKeyRequest::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
    544     return deserialize_key_blob(&key_blob, buf_ptr, end) &&
    545            upgrade_params.Deserialize(buf_ptr, end);
    546 }
    547 
    548 UpgradeKeyResponse::~UpgradeKeyResponse() {
    549     delete[] upgraded_key.key_material;
    550 }
    551 
    552 size_t UpgradeKeyResponse::NonErrorSerializedSize() const {
    553     return key_blob_size(upgraded_key);
    554 }
    555 
    556 uint8_t* UpgradeKeyResponse::NonErrorSerialize(uint8_t* buf, const uint8_t* end) const {
    557     return serialize_key_blob(upgraded_key, buf, end);
    558 }
    559 
    560 bool UpgradeKeyResponse::NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) {
    561     return deserialize_key_blob(&upgraded_key, buf_ptr, end);
    562 }
    563 
    564 }  // namespace keymaster
    565