1#include "cache.h"2#include "tag.h"34/*5* A signature file has a very simple fixed format: four lines6* of "object <sha1>" + "type <typename>" + "tag <tagname>" +7* "tagger <committer>", followed by a blank line, a free-form tag8* message and a signature block that git itself doesn't care about,9* but that can be verified with gpg or similar.10*11* The first three lines are guaranteed to be at least 63 bytes:12* "object <sha1>\n" is 48 bytes, "type tag\n" at 9 bytes is the13* shortest possible type-line, and "tag .\n" at 6 bytes is the14* shortest single-character-tag line.15*16* We also artificially limit the size of the full object to 8kB.17* Just because I'm a lazy bastard, and if you can't fit a signature18* in that size, you're doing something wrong.19*/2021/* Some random size */22#define MAXSIZE (8192)2324/*25* We refuse to tag something we can't verify. Just because.26*/27static int verify_object(unsigned char *sha1, const char *expected_type)28{29int ret = -1;30enum object_type type;31unsigned long size;32void *buffer = read_sha1_file(sha1, &type, &size);3334if (buffer) {35if (type == type_from_string(expected_type))36ret = check_sha1_signature(sha1, buffer, size, expected_type);37free(buffer);38}39return ret;40}4142#ifdef NO_C99_FORMAT43#define PD_FMT "%d"44#else45#define PD_FMT "%td"46#endif4748static int verify_tag(char *buffer, unsigned long size)49{50int typelen;51char type[20];52unsigned char sha1[20];53const char *object, *type_line, *tag_line, *tagger_line;5455if (size < 64)56return error("wanna fool me ? you obviously got the size wrong !");5758buffer[size] = 0;5960/* Verify object line */61object = buffer;62if (memcmp(object, "object ", 7))63return error("char%d: does not start with \"object \"", 0);6465if (get_sha1_hex(object + 7, sha1))66return error("char%d: could not get SHA1 hash", 7);6768/* Verify type line */69type_line = object + 48;70if (memcmp(type_line - 1, "\ntype ", 6))71return error("char%d: could not find \"\\ntype \"", 47);7273/* Verify tag-line */74tag_line = strchr(type_line, '\n');75if (!tag_line)76return error("char" PD_FMT ": could not find next \"\\n\"", type_line - buffer);77tag_line++;78if (memcmp(tag_line, "tag ", 4) || tag_line[4] == '\n')79return error("char" PD_FMT ": no \"tag \" found", tag_line - buffer);8081/* Get the actual type */82typelen = tag_line - type_line - strlen("type \n");83if (typelen >= sizeof(type))84return error("char" PD_FMT ": type too long", type_line+5 - buffer);8586memcpy(type, type_line+5, typelen);87type[typelen] = 0;8889/* Verify that the object matches */90if (verify_object(sha1, type))91return error("char%d: could not verify object %s", 7, sha1_to_hex(sha1));9293/* Verify the tag-name: we don't allow control characters or spaces in it */94tag_line += 4;95for (;;) {96unsigned char c = *tag_line++;97if (c == '\n')98break;99if (c > ' ')100continue;101return error("char" PD_FMT ": could not verify tag name", tag_line - buffer);102}103104/* Verify the tagger line */105tagger_line = tag_line;106107if (memcmp(tagger_line, "tagger", 6) || (tagger_line[6] == '\n'))108return error("char" PD_FMT ": could not find \"tagger\"", tagger_line - buffer);109110/* TODO: check for committer info + blank line? */111/* Also, the minimum length is probably + "tagger .", or 63+8=71 */112113/* The actual stuff afterwards we don't care about.. */114return 0;115}116117#undef PD_FMT118119int main(int argc, char **argv)120{121unsigned long size = 4096;122char *buffer = xmalloc(size);123unsigned char result_sha1[20];124125if (argc != 1)126usage("git-mktag < signaturefile");127128setup_git_directory();129130if (read_pipe(0, &buffer, &size)) {131free(buffer);132die("could not read from stdin");133}134135/* Verify it for some basic sanity: it needs to start with136"object <sha1>\ntype\ntagger " */137if (verify_tag(buffer, size) < 0)138die("invalid tag signature file");139140if (write_sha1_file(buffer, size, tag_type, result_sha1) < 0)141die("unable to write tag file");142143free(buffer);144145printf("%s\n", sha1_to_hex(result_sha1));146return 0;147}