123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447 |
- #ifndef _IPXE_PCCRC_H
- #define _IPXE_PCCRC_H
-
- /** @file
- *
- * Peer Content Caching and Retrieval: Content Identification [MS-PCCRC]
- *
- */
-
- FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
-
- #include <stdint.h>
- #include <byteswap.h>
- #include <ipxe/uaccess.h>
- #include <ipxe/crypto.h>
-
- /******************************************************************************
- *
- * Content Information versioning
- *
- ******************************************************************************
- *
- * Note that version 1 data structures are little-endian, but version
- * 2 data structures are big-endian.
- */
-
- /** Content Information version number */
- union peerdist_info_version {
- /** Raw version number
- *
- * Always little-endian, regardless of whether the
- * encompassing structure is version 1 (little-endian) or
- * version 2 (big-endian).
- */
- uint16_t raw;
- /** Major:minor version number */
- struct {
- /** Minor version number */
- uint8_t minor;
- /** Major version number */
- uint8_t major;
- } __attribute__ (( packed ));
- } __attribute__ (( packed ));
-
- /** Content Information version 1 */
- #define PEERDIST_INFO_V1 0x0100
-
- /** Content Information version 2 */
- #define PEERDIST_INFO_V2 0x0200
-
- /******************************************************************************
- *
- * Content Information version 1
- *
- ******************************************************************************
- */
-
- /** Content Information version 1 data structure header
- *
- * All fields are little-endian.
- */
- struct peerdist_info_v1 {
- /** Version number */
- union peerdist_info_version version;
- /** Hash algorithm
- *
- * This is a @c PEERDIST_INFO_V1_HASH_XXX constant.
- */
- uint32_t hash;
- /** Length to skip in first segment
- *
- * Length at the start of the first segment which is not
- * included within the content range.
- */
- uint32_t first;
- /** Length to read in last segment, or zero
- *
- * Length within the last segment which is included within the
- * content range. A zero value indicates that the whole of
- * the last segment is included within the content range.
- */
- uint32_t last;
- /** Number of segments within the content information */
- uint32_t segments;
- /* Followed by a variable-length array of segment descriptions
- * and a list of variable-length block descriptions:
- *
- * peerdist_info_v1_segment_t(digestsize) segment[segments];
- * peerdist_info_v1_block_t(digestsize, block0.blocks) block0;
- * peerdist_info_v1_block_t(digestsize, block1.blocks) block1;
- * ...
- * peerdist_info_v1_block_t(digestsize, blockN.blocks) blockN;
- */
- } __attribute__ (( packed ));
-
- /** SHA-256 hash algorithm */
- #define PEERDIST_INFO_V1_HASH_SHA256 0x0000800cUL
-
- /** SHA-384 hash algorithm */
- #define PEERDIST_INFO_V1_HASH_SHA384 0x0000800dUL
-
- /** SHA-512 hash algorithm */
- #define PEERDIST_INFO_V1_HASH_SHA512 0x0000800eUL
-
- /** Content Information version 1 segment description header
- *
- * All fields are little-endian.
- */
- struct peerdist_info_v1_segment {
- /** Offset of this segment within the content */
- uint64_t offset;
- /** Length of this segment
- *
- * Should always be 32MB, except for the last segment within
- * the content.
- */
- uint32_t len;
- /** Block size for this segment
- *
- * Should always be 64kB. Note that the last block within the
- * last segment may actually be less than 64kB.
- */
- uint32_t blksize;
- /* Followed by two variable-length hashes:
- *
- * uint8_t hash[digestsize];
- * uint8_t secret[digestsize];
- *
- * where digestsize is the digest size for the selected hash
- * algorithm.
- *
- * Note that the hash is taken over (the hashes of all blocks
- * within) the entire segment, even if the blocks do not
- * intersect the content range (and so do not appear within
- * the block list). It therefore functions only as a segment
- * identifier; it cannot be used to verify the content of the
- * segment (since we may not download all blocks within the
- * segment).
- */
- } __attribute__ (( packed ));
-
- /** Content Information version 1 segment description
- *
- * @v digestsize Digest size
- */
- #define peerdist_info_v1_segment_t( digestsize ) \
- struct { \
- struct peerdist_info_v1_segment segment; \
- uint8_t hash[digestsize]; \
- uint8_t secret[digestsize]; \
- } __attribute__ (( packed ))
-
- /** Content Information version 1 block description header
- *
- * All fields are little-endian.
- */
- struct peerdist_info_v1_block {
- /** Number of blocks within the block description
- *
- * This is the number of blocks within the segment which
- * overlap the content range. It may therefore be less than
- * the number of blocks within the segment.
- */
- uint32_t blocks;
- /* Followed by an array of variable-length hashes:
- *
- * uint8_t hash[blocks][digestsize];
- *
- * where digestsize is the digest size for the selected hash
- * algorithm.
- */
- } __attribute__ (( packed ));
-
- /** Content Information version 1 block description
- *
- * @v digestsize Digest size
- * @v blocks Number of blocks
- */
- #define peerdist_info_v1_block_t( digestsize, blocks ) \
- struct { \
- struct peerdist_info_v1_block block; \
- uint8_t hash[blocks][digestsize]; \
- } __attribute__ (( packed ))
-
- /******************************************************************************
- *
- * Content Information version 2
- *
- ******************************************************************************
- */
-
- /** Content Information version 2 data structure header
- *
- * All fields are big-endian.
- */
- struct peerdist_info_v2 {
- /** Version number */
- union peerdist_info_version version;
- /** Hash algorithm
- *
- * This is a @c PEERDIST_INFO_V2_HASH_XXX constant.
- */
- uint8_t hash;
- /** Offset of the first segment within the content */
- uint64_t offset;
- /** Index of the first segment within the content */
- uint64_t index;
- /** Length to skip in first segment
- *
- * Length at the start of the first segment which is not
- * included within the content range.
- */
- uint32_t first;
- /** Length of content range, or zero
- *
- * Length of the content range. A zero indicates that
- * everything up to the end of the last segment is included in
- * the content range.
- */
- uint64_t len;
- /* Followed by a list of chunk descriptions */
- } __attribute__ (( packed ));
-
- /** SHA-512 hash algorithm with output truncated to first 256 bits */
- #define PEERDIST_INFO_V2_HASH_SHA512_TRUNC 0x04
-
- /** Content Information version 2 chunk description header
- *
- * All fields are big-endian.
- */
- struct peerdist_info_v2_chunk {
- /** Chunk type */
- uint8_t type;
- /** Chunk data length */
- uint32_t len;
- /* Followed by an array of segment descriptions:
- *
- * peerdist_info_v2_segment_t(digestsize) segment[segments]
- *
- * where digestsize is the digest size for the selected hash
- * algorithm, and segments is equal to @c len divided by the
- * size of each segment array entry.
- */
- } __attribute__ (( packed ));
-
- /** Content Information version 2 chunk description
- *
- * @v digestsize Digest size
- */
- #define peerdist_info_v2_chunk_t( digestsize ) \
- struct { \
- struct peerdist_info_v2_chunk chunk; \
- peerdist_info_v2_segment_t ( digestsize ) segment[0]; \
- } __attribute__ (( packed ))
-
- /** Chunk type */
- #define PEERDIST_INFO_V2_CHUNK_TYPE 0x00
-
- /** Content Information version 2 segment description header
- *
- * All fields are big-endian.
- */
- struct peerdist_info_v2_segment {
- /** Segment length */
- uint32_t len;
- /* Followed by two variable-length hashes:
- *
- * uint8_t hash[digestsize];
- * uint8_t secret[digestsize];
- *
- * where digestsize is the digest size for the selected hash
- * algorithm.
- */
- } __attribute__ (( packed ));
-
- /** Content Information version 2 segment description
- *
- * @v digestsize Digest size
- */
- #define peerdist_info_v2_segment_t( digestsize ) \
- struct { \
- struct peerdist_info_v2_segment segment; \
- uint8_t hash[digestsize]; \
- uint8_t secret[digestsize]; \
- } __attribute__ (( packed ))
-
- /******************************************************************************
- *
- * Content Information
- *
- ******************************************************************************
- */
-
- /** Maximum digest size for any supported algorithm
- *
- * The largest digest size that we support is for SHA-512 at 64 bytes
- */
- #define PEERDIST_DIGEST_MAX_SIZE 64
-
- /** Raw content information */
- struct peerdist_raw {
- /** Data buffer */
- userptr_t data;
- /** Length of data buffer */
- size_t len;
- };
-
- /** A content range */
- struct peerdist_range {
- /** Start offset */
- size_t start;
- /** End offset */
- size_t end;
- };
-
- /** Content information */
- struct peerdist_info {
- /** Raw content information */
- struct peerdist_raw raw;
-
- /** Content information operations */
- struct peerdist_info_operations *op;
- /** Digest algorithm */
- struct digest_algorithm *digest;
- /** Digest size
- *
- * Note that this may be shorter than the digest size of the
- * digest algorithm. The truncation does not always take
- * place as soon as a digest is calculated. For example,
- * version 2 content information uses SHA-512 with a truncated
- * digest size of 32 (256 bits), but the segment identifier
- * ("HoHoDk") is calculated by using HMAC with the full
- * SHA-512 digest and then truncating the HMAC output, rather
- * than by simply using HMAC with the truncated SHA-512
- * digest. This is, of course, totally undocumented.
- */
- size_t digestsize;
- /** Content range */
- struct peerdist_range range;
- /** Trimmed content range */
- struct peerdist_range trim;
- /** Number of segments within the content information */
- unsigned int segments;
- };
-
- /** A content information segment */
- struct peerdist_info_segment {
- /** Content information */
- const struct peerdist_info *info;
- /** Segment index */
- unsigned int index;
-
- /** Content range
- *
- * Note that this range may exceed the overall content range.
- */
- struct peerdist_range range;
- /** Number of blocks within this segment */
- unsigned int blocks;
- /** Block size */
- size_t blksize;
- /** Segment hash of data
- *
- * This is MS-PCCRC's "HoD".
- */
- uint8_t hash[PEERDIST_DIGEST_MAX_SIZE];
- /** Segment secret
- *
- * This is MS-PCCRC's "Ke = Kp".
- */
- uint8_t secret[PEERDIST_DIGEST_MAX_SIZE];
- /** Segment identifier
- *
- * This is MS-PCCRC's "HoHoDk".
- */
- uint8_t id[PEERDIST_DIGEST_MAX_SIZE];
- };
-
- /** Magic string constant used to calculate segment identifier
- *
- * Note that the MS-PCCRC specification states that this constant is
- *
- * "the null-terminated ASCII string constant "MS_P2P_CACHING";
- * string literals are all ASCII strings with NULL terminators
- * unless otherwise noted."
- *
- * The specification lies. This constant is a UTF-16LE string, not an
- * ASCII string. The terminating wNUL *is* included within the
- * constant.
- */
- #define PEERDIST_SEGMENT_ID_MAGIC L"MS_P2P_CACHING"
-
- /** A content information block */
- struct peerdist_info_block {
- /** Content information segment */
- const struct peerdist_info_segment *segment;
- /** Block index */
- unsigned int index;
-
- /** Content range
- *
- * Note that this range may exceed the overall content range.
- */
- struct peerdist_range range;
- /** Trimmed content range */
- struct peerdist_range trim;
- /** Block hash */
- uint8_t hash[PEERDIST_DIGEST_MAX_SIZE];
- };
-
- /** Content information operations */
- struct peerdist_info_operations {
- /**
- * Populate content information
- *
- * @v info Content information to fill in
- * @ret rc Return status code
- */
- int ( * info ) ( struct peerdist_info *info );
- /**
- * Populate content information segment
- *
- * @v segment Content information segment to fill in
- * @ret rc Return status code
- */
- int ( * segment ) ( struct peerdist_info_segment *segment );
- /**
- * Populate content information block
- *
- * @v block Content information block to fill in
- * @ret rc Return status code
- */
- int ( * block ) ( struct peerdist_info_block *block );
- };
-
- extern struct digest_algorithm sha512_trunc_algorithm;
-
- extern int peerdist_info ( userptr_t data, size_t len,
- struct peerdist_info *info );
- extern int peerdist_info_segment ( const struct peerdist_info *info,
- struct peerdist_info_segment *segment,
- unsigned int index );
- extern int peerdist_info_block ( const struct peerdist_info_segment *segment,
- struct peerdist_info_block *block,
- unsigned int index );
-
- #endif /* _IPXE_PCCRC_H */
|