- SilcBuffer buf;
- SilcPKCS alg;
- SilcUInt16 pkcs_len, identifier_len;
- SilcUInt32 totlen, key_len;
- unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
- int ret;
-
- buf = silc_buffer_alloc(data_len);
- silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
- silc_buffer_put(buf, data, data_len);
-
- /* Get length */
- ret = silc_buffer_unformat(buf,
- SILC_STR_UI_INT(&totlen),
- SILC_STR_END);
- if (ret == -1) {
- silc_buffer_free(buf);
- return FALSE;
- }
-
- if (totlen != data_len) {
- silc_buffer_free(buf);
- return FALSE;
- }
-
- /* Get algorithm name and identifier */
- silc_buffer_pull(buf, 4);
- ret =
- silc_buffer_unformat(buf,
- SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
- SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
- SILC_STR_END);
- if (ret == -1)
- goto err;
-
- if (pkcs_len < 1 || identifier_len < 3 ||
- pkcs_len + identifier_len > totlen)
- goto err;
-
- /* See if we support this algorithm (check only if PKCS are registered) */
- if (SILC_PKCS_LIST && !silc_pkcs_is_supported(pkcs_name)) {
- SILC_LOG_DEBUG(("Unknown PKCS %s", pkcs_name));
- goto err;
- }
-
- /* Protocol says that at least UN and HN must be provided as identifier,
- check for these. */
- if (!strstr(ident, "UN=") && !strstr(ident, "HN=")) {
- SILC_LOG_DEBUG(("The public does not have the required UN= and HN= "
- "identifiers"));
- goto err;
- }
-
- /* Get key data. We assume that rest of the buffer is key data. */
- silc_buffer_pull(buf, 2 + pkcs_len + 2 + identifier_len);
- key_len = buf->len;
- ret = silc_buffer_unformat(buf,
- SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
- SILC_STR_END);
- if (ret == -1)
- goto err;
-
- /* Try to set the key. If this fails the key must be malformed. This
- code assumes that the PKCS routine checks the format of the key.
- (check only if PKCS are registered) */
- if (SILC_PKCS_LIST) {
- silc_pkcs_alloc(pkcs_name, &alg);
- if (!alg->pkcs->set_public_key(alg->context, key_data, key_len))
- goto err;
- silc_pkcs_free(alg);
- }
-
- if (public_key) {
- *public_key = silc_calloc(1, sizeof(**public_key));
- (*public_key)->len = totlen;
- (*public_key)->name = pkcs_name;
- (*public_key)->identifier = ident;
- (*public_key)->pk = key_data;
- (*public_key)->pk_len = key_len;
- }
-
- silc_buffer_free(buf);
- return TRUE;
-
- err:
- if (pkcs_name)
- silc_free(pkcs_name);
- if (ident)
- silc_free(ident);
- if (key_data)
- silc_free(key_data);
- silc_buffer_free(buf);
- return FALSE;