/* This file is part of GNUnet. Copyright (C) 2009-2013, 2016 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . SPDX-License-Identifier: AGPL3.0-or-later */ /** * @file credential/credential_serialization.c * @brief API to serialize and deserialize delegation chains * and credentials * @author Martin Schanzenbach */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_constants.h" #include "gnunet_credential_service.h" #include "gnunet_signatures.h" #include "credential.h" /** * Calculate how many bytes we will need to serialize * the given delegation chain * * @param ds_count number of delegation chain entries * @param dsr array of #GNUNET_CREDENTIAL_DelegationSet * @return the required size to serialize */ size_t GNUNET_CREDENTIAL_delegation_set_get_size (unsigned int ds_count, const struct GNUNET_CREDENTIAL_DelegationSet *dsr) { unsigned int i; size_t ret; ret = sizeof(struct DelegationRecordData) * (ds_count); for (i = 0; i < ds_count; i++) { GNUNET_assert ((ret + dsr[i].subject_attribute_len) >= ret); ret += dsr[i].subject_attribute_len; } return ret; } /** * Serizalize the given delegation chain entries and credential * * @param d_count number of delegation chain entries * @param dsr array of #GNUNET_CREDENTIAL_DelegationSet * @param dest_size size of the destination * @param dest where to store the result * @return the size of the data, -1 on failure */ ssize_t GNUNET_CREDENTIAL_delegation_set_serialize (unsigned int d_count, const struct GNUNET_CREDENTIAL_DelegationSet *dsr, size_t dest_size, char *dest) { struct DelegationRecordData rec; unsigned int i; size_t off; off = 0; for (i = 0; i < d_count; i++) { rec.subject_attribute_len = htonl ((uint32_t) dsr[i].subject_attribute_len); rec.subject_key = dsr[i].subject_key; if (off + sizeof(rec) > dest_size) return -1; GNUNET_memcpy (&dest[off], &rec, sizeof(rec)); off += sizeof(rec); if (0 == dsr[i].subject_attribute_len) continue; if (off + dsr[i].subject_attribute_len > dest_size) return -1; GNUNET_memcpy (&dest[off], dsr[i].subject_attribute, dsr[i].subject_attribute_len); off += dsr[i].subject_attribute_len; } return off; } /** * Deserialize the given destination * * @param len size of the serialized delegation chain and cred * @param src the serialized data * @param d_count the number of delegation chain entries * @param dsr where to put the delegation chain entries * @return #GNUNET_OK on success, #GNUNET_SYSERR on error */ int GNUNET_CREDENTIAL_delegation_set_deserialize (size_t len, const char *src, unsigned int d_count, struct GNUNET_CREDENTIAL_DelegationSet * dsr) { struct DelegationRecordData rec; unsigned int i; size_t off; off = 0; for (i = 0; i < d_count; i++) { if (off + sizeof(rec) > len) return GNUNET_SYSERR; GNUNET_memcpy (&rec, &src[off], sizeof(rec)); dsr[i].subject_key = rec.subject_key; off += sizeof(rec); dsr[i].subject_attribute_len = ntohl ((uint32_t) rec.subject_attribute_len); if (off + dsr[i].subject_attribute_len > len) return GNUNET_SYSERR; dsr[i].subject_attribute = (char*) &src[off]; off += dsr[i].subject_attribute_len; } return GNUNET_OK; } /** * Calculate how many bytes we will need to serialize * the credentials * * @param c_count number of credential entries * @param cd a #GNUNET_CREDENTIAL_Credential * @return the required size to serialize */ size_t GNUNET_CREDENTIAL_credentials_get_size (unsigned int c_count, const struct GNUNET_CREDENTIAL_Credential *cd) { unsigned int i; size_t ret; ret = sizeof(struct CredentialEntry) * (c_count); for (i = 0; i < c_count; i++) { GNUNET_assert ((ret + cd[i].issuer_attribute_len) >= ret); ret += cd[i].issuer_attribute_len; } return ret; } /** * Serizalize the given credentials * * @param c_count number of credential entries * @param cd a #GNUNET_CREDENTIAL_Credential * @param dest_size size of the destination * @param dest where to store the result * @return the size of the data, -1 on failure */ ssize_t GNUNET_CREDENTIAL_credentials_serialize (unsigned int c_count, const struct GNUNET_CREDENTIAL_Credential *cd, size_t dest_size, char *dest) { struct CredentialEntry c_rec; unsigned int i; size_t off; off = 0; for (i = 0; i < c_count; i++) { c_rec.issuer_attribute_len = htonl ((uint32_t) cd[i].issuer_attribute_len); c_rec.issuer_key = cd[i].issuer_key; c_rec.subject_key = cd[i].subject_key; c_rec.signature = cd[i].signature; c_rec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CREDENTIAL); c_rec.purpose.size = htonl ((sizeof(struct CredentialEntry) + cd[i].issuer_attribute_len) - sizeof(struct GNUNET_CRYPTO_EcdsaSignature)); c_rec.expiration = GNUNET_htonll (cd[i].expiration.abs_value_us); if (off + sizeof(c_rec) > dest_size) return -1; GNUNET_memcpy (&dest[off], &c_rec, sizeof(c_rec)); off += sizeof(c_rec); if (off + cd[i].issuer_attribute_len > dest_size) return -1; GNUNET_memcpy (&dest[off], cd[i].issuer_attribute, cd[i].issuer_attribute_len); off += cd[i].issuer_attribute_len; } return off; } /** * Deserialize the given destination * * @param len size of the serialized creds * @param src the serialized data * @param c_count the number of credential entries * @param cd where to put the credential data * @return #GNUNET_OK on success, #GNUNET_SYSERR on error */ int GNUNET_CREDENTIAL_credentials_deserialize (size_t len, const char *src, unsigned int c_count, struct GNUNET_CREDENTIAL_Credential * cd) { struct CredentialEntry c_rec; unsigned int i; size_t off; off = 0; for (i = 0; i < c_count; i++) { if (off + sizeof(c_rec) > len) return GNUNET_SYSERR; GNUNET_memcpy (&c_rec, &src[off], sizeof(c_rec)); cd[i].issuer_attribute_len = ntohl ((uint32_t) c_rec.issuer_attribute_len); cd[i].issuer_key = c_rec.issuer_key; cd[i].subject_key = c_rec.subject_key; cd[i].signature = c_rec.signature; cd[i].expiration.abs_value_us = GNUNET_ntohll (c_rec.expiration); off += sizeof(c_rec); if (off + cd[i].issuer_attribute_len > len) return GNUNET_SYSERR; cd[i].issuer_attribute = &src[off]; off += cd[i].issuer_attribute_len; } return GNUNET_OK; } /** * Calculate how many bytes we will need to serialize * the given delegation chain and credential * * @param d_count number of delegation chain entries * @param dd array of #GNUNET_CREDENTIAL_Delegation * @param c_count number of credential entries * @param cd a #GNUNET_CREDENTIAL_Credential * @return the required size to serialize */ size_t GNUNET_CREDENTIAL_delegation_chain_get_size (unsigned int d_count, const struct GNUNET_CREDENTIAL_Delegation *dd, unsigned int c_count, const struct GNUNET_CREDENTIAL_Credential *cd) { unsigned int i; size_t ret; ret = sizeof(struct ChainEntry) * (d_count); for (i = 0; i < d_count; i++) { GNUNET_assert ((ret + dd[i].issuer_attribute_len + dd[i].subject_attribute_len) >= ret); ret += dd[i].issuer_attribute_len + dd[i].subject_attribute_len; } return ret + GNUNET_CREDENTIAL_credentials_get_size (c_count, cd); } /** * Serizalize the given delegation chain entries and credential * * @param d_count number of delegation chain entries * @param dd array of #GNUNET_CREDENTIAL_Delegation * @param c_count number of credential entries * @param cd a #GNUNET_CREDENTIAL_Credential * @param dest_size size of the destination * @param dest where to store the result * @return the size of the data, -1 on failure */ ssize_t GNUNET_CREDENTIAL_delegation_chain_serialize (unsigned int d_count, const struct GNUNET_CREDENTIAL_Delegation *dd, unsigned int c_count, const struct GNUNET_CREDENTIAL_Credential *cd, size_t dest_size, char *dest) { struct ChainEntry rec; unsigned int i; size_t off; off = 0; for (i = 0; i < d_count; i++) { rec.issuer_attribute_len = htonl ((uint32_t) dd[i].issuer_attribute_len); rec.subject_attribute_len = htonl ((uint32_t) dd[i].subject_attribute_len); rec.issuer_key = dd[i].issuer_key; rec.subject_key = dd[i].subject_key; if (off + sizeof(rec) > dest_size) return -1; GNUNET_memcpy (&dest[off], &rec, sizeof(rec)); off += sizeof(rec); if (off + dd[i].issuer_attribute_len > dest_size) return -1; GNUNET_memcpy (&dest[off], dd[i].issuer_attribute, dd[i].issuer_attribute_len); off += dd[i].issuer_attribute_len; if (0 == dd[i].subject_attribute_len) continue; if (off + dd[i].subject_attribute_len > dest_size) return -1; GNUNET_memcpy (&dest[off], dd[i].subject_attribute, dd[i].subject_attribute_len); off += dd[i].subject_attribute_len; } return off + GNUNET_CREDENTIAL_credentials_serialize (c_count, cd, dest_size - off, &dest[off]); } /** * Deserialize the given destination * * @param len size of the serialized delegation chain and cred * @param src the serialized data * @param d_count the number of delegation chain entries * @param dd where to put the delegation chain entries * @param c_count the number of credential entries * @param cd where to put the credential data * @return #GNUNET_OK on success, #GNUNET_SYSERR on error */ int GNUNET_CREDENTIAL_delegation_chain_deserialize (size_t len, const char *src, unsigned int d_count, struct GNUNET_CREDENTIAL_Delegation *dd, unsigned int c_count, struct GNUNET_CREDENTIAL_Credential *cd) { struct ChainEntry rec; unsigned int i; size_t off; off = 0; for (i = 0; i < d_count; i++) { if (off + sizeof(rec) > len) return GNUNET_SYSERR; GNUNET_memcpy (&rec, &src[off], sizeof(rec)); dd[i].issuer_attribute_len = ntohl ((uint32_t) rec.issuer_attribute_len); dd[i].issuer_key = rec.issuer_key; dd[i].subject_key = rec.subject_key; off += sizeof(rec); if (off + dd[i].issuer_attribute_len > len) return GNUNET_SYSERR; dd[i].issuer_attribute = &src[off]; off += dd[i].issuer_attribute_len; dd[i].subject_attribute_len = ntohl ((uint32_t) rec.subject_attribute_len); if (off + dd[i].subject_attribute_len > len) return GNUNET_SYSERR; dd[i].subject_attribute = &src[off]; off += dd[i].subject_attribute_len; } return GNUNET_CREDENTIAL_credentials_deserialize (len - off, &src[off], c_count, cd); } int GNUNET_CREDENTIAL_credential_serialize (struct GNUNET_CREDENTIAL_Credential *cred, char **data) { size_t size; struct CredentialEntry *cdata; size = sizeof(struct CredentialEntry) + strlen (cred->issuer_attribute) + 1; *data = GNUNET_malloc (size); cdata = (struct CredentialEntry*) *data; cdata->subject_key = cred->subject_key; cdata->issuer_key = cred->issuer_key; cdata->expiration = GNUNET_htonll (cred->expiration.abs_value_us); cdata->signature = cred->signature; cdata->issuer_attribute_len = htonl (strlen (cred->issuer_attribute) + 1); cdata->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CREDENTIAL); cdata->purpose.size = htonl (size - sizeof(struct GNUNET_CRYPTO_EcdsaSignature)); GNUNET_memcpy (&cdata[1], cred->issuer_attribute, strlen (cred->issuer_attribute)); if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_verify ( GNUNET_SIGNATURE_PURPOSE_CREDENTIAL, &cdata->purpose, &cdata->signature, &cdata->issuer_key)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Invalid credential\n"); // return NULL; } return size; } struct GNUNET_CREDENTIAL_Credential* GNUNET_CREDENTIAL_credential_deserialize (const char*data, size_t data_size) { struct GNUNET_CREDENTIAL_Credential *cred; struct CredentialEntry *cdata; char *issuer_attribute; if (data_size < sizeof(struct CredentialEntry)) return NULL; cdata = (struct CredentialEntry*) data; if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_verify ( GNUNET_SIGNATURE_PURPOSE_CREDENTIAL, &cdata->purpose, &cdata->signature, &cdata->issuer_key)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Invalid credential\n"); // return NULL; } issuer_attribute = (char*) &cdata[1]; cred = GNUNET_malloc (sizeof(struct GNUNET_CREDENTIAL_Credential) + ntohl ( cdata->issuer_attribute_len)); cred->issuer_key = cdata->issuer_key; cred->subject_key = cdata->subject_key; GNUNET_memcpy (&cred[1], issuer_attribute, ntohl (cdata->issuer_attribute_len)); cred->signature = cdata->signature; cred->issuer_attribute = (char*) &cred[1]; cred->expiration.abs_value_us = GNUNET_ntohll (cdata->expiration); return cred; } /* end of credential_serialization.c */