1#include"cache.h" 2 3/* 4 * A signature file has a very simple fixed format: three lines 5 * of "object <sha1>" + "type <typename>" + "tag <tagname>", 6 * followed by some free-form signature that git itself doesn't 7 * care about, but that can be verified with gpg or similar. 8 * 9 * The first three lines are guaranteed to be at least 63 bytes: 10 * "object <sha1>\n" is 48 bytes, "type tag\n" at 9 bytes is the 11 * shortest possible type-line, and "tag .\n" at 6 bytes is the 12 * shortest single-character-tag line. 13 * 14 * We also artificially limit the size of the full object to 8kB. 15 * Just because I'm a lazy bastard, and if you can't fit a signature 16 * in that size, you're doing something wrong. 17 */ 18 19// Some random size 20#define MAXSIZE (8192) 21 22/* 23 * We refuse to tag something we can't verify. Just because. 24 */ 25static intverify_object(unsigned char*sha1,const char*expected_type) 26{ 27int ret = -1; 28char type[100]; 29unsigned long size; 30void*buffer =read_sha1_file(sha1, type, &size); 31 32if(buffer) { 33if(!strcmp(type, expected_type)) 34 ret =check_sha1_signature(sha1, buffer, size, type); 35free(buffer); 36} 37return ret; 38} 39 40static intverify_tag(char*buffer,unsigned long size) 41{ 42int typelen; 43char type[20]; 44unsigned char sha1[20]; 45const char*object, *type_line, *tag_line, *tagger_line; 46 47if(size <64|| size > MAXSIZE-1) 48return-1; 49 buffer[size] =0; 50 51/* Verify object line */ 52 object = buffer; 53if(memcmp(object,"object ",7)) 54return-1; 55if(get_sha1_hex(object +7, sha1)) 56return-1; 57 58/* Verify type line */ 59 type_line = object +48; 60if(memcmp(type_line -1,"\ntype ",6)) 61return-1; 62 63/* Verify tag-line */ 64 tag_line =strchr(type_line,'\n'); 65if(!tag_line) 66return-1; 67 tag_line++; 68if(memcmp(tag_line,"tag ",4) || tag_line[4] =='\n') 69return-1; 70 71/* Get the actual type */ 72 typelen = tag_line - type_line -strlen("type\n"); 73if(typelen >=sizeof(type)) 74return-1; 75memcpy(type, type_line+5, typelen); 76 type[typelen] =0; 77 78/* Verify that the object matches */ 79if(get_sha1_hex(object +7, sha1)) 80return-1; 81if(verify_object(sha1, type)) 82return-1; 83 84/* Verify the tag-name: we don't allow control characters or spaces in it */ 85 tag_line +=4; 86for(;;) { 87unsigned char c = *tag_line++; 88if(c =='\n') 89break; 90if(c >' ') 91continue; 92return-1; 93} 94 95/* Verify the tagger line */ 96 tagger_line = tag_line; 97 98if(memcmp(tagger_line,"tagger",6) || (tagger_line[6] =='\n')) 99return-1; 100 101/* The actual stuff afterwards we don't care about.. */ 102return0; 103} 104 105intmain(int argc,char**argv) 106{ 107unsigned long size; 108char buffer[MAXSIZE]; 109unsigned char result_sha1[20]; 110 111if(argc !=1) 112usage("cat <signaturefile> | git-mktag"); 113 114setup_git_directory(); 115 116// Read the signature 117 size =0; 118for(;;) { 119int ret =read(0, buffer + size, MAXSIZE - size); 120if(!ret) 121break; 122if(ret <0) { 123if(errno == EAGAIN) 124continue; 125break; 126} 127 size += ret; 128} 129 130// Verify it for some basic sanity: it needs to start with "object <sha1>\ntype\ntagger " 131if(verify_tag(buffer, size) <0) 132die("invalid tag signature file"); 133 134if(write_sha1_file(buffer, size,"tag", result_sha1) <0) 135die("unable to write tag file"); 136printf("%s\n",sha1_to_hex(result_sha1)); 137return0; 138}