1#include"cache.h" 2#include"tag.h" 3 4/* 5 * A signature file has a very simple fixed format: four lines 6 * of "object <sha1>" + "type <typename>" + "tag <tagname>" + 7 * "tagger <committer>", followed by a blank line, a free-form tag 8 * 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 four lines are guaranteed to be at least 83 bytes: 12 * "object <sha1>\n" is 48 bytes, "type tag\n" at 9 bytes is the 13 * shortest possible type-line, "tag .\n" at 6 bytes is the shortest 14 * single-character-tag line, and "tagger . <> 0 +0000\n" at 20 bytes is 15 * the shortest possible tagger-line. 16 */ 17 18/* 19 * We refuse to tag something we can't verify. Just because. 20 */ 21static intverify_object(unsigned char*sha1,const char*expected_type) 22{ 23int ret = -1; 24enum object_type type; 25unsigned long size; 26void*buffer =read_sha1_file(sha1, &type, &size); 27 28if(buffer) { 29if(type ==type_from_string(expected_type)) 30 ret =check_sha1_signature(sha1, buffer, size, expected_type); 31free(buffer); 32} 33return ret; 34} 35 36#ifdef NO_C99_FORMAT 37#define PD_FMT"%d" 38#else 39#define PD_FMT"%td" 40#endif 41 42static intverify_tag(char*buffer,unsigned long size) 43{ 44int typelen; 45char type[20]; 46unsigned char sha1[20]; 47const char*object, *type_line, *tag_line, *tagger_line, *lb, *rb; 48size_t len; 49 50if(size <84) 51returnerror("wanna fool me ? you obviously got the size wrong !"); 52 53 buffer[size] =0; 54 55/* Verify object line */ 56 object = buffer; 57if(memcmp(object,"object ",7)) 58returnerror("char%d: does not start with\"object\"",0); 59 60if(get_sha1_hex(object +7, sha1)) 61returnerror("char%d: could not get SHA1 hash",7); 62 63/* Verify type line */ 64 type_line = object +48; 65if(memcmp(type_line -1,"\ntype ",6)) 66returnerror("char%d: could not find\"\\ntype\"",47); 67 68/* Verify tag-line */ 69 tag_line =strchr(type_line,'\n'); 70if(!tag_line) 71returnerror("char" PD_FMT ": could not find next\"\\n\"", type_line - buffer); 72 tag_line++; 73if(memcmp(tag_line,"tag ",4) || tag_line[4] =='\n') 74returnerror("char" PD_FMT ": no\"tag\"found", tag_line - buffer); 75 76/* Get the actual type */ 77 typelen = tag_line - type_line -strlen("type\n"); 78if(typelen >=sizeof(type)) 79returnerror("char" PD_FMT ": type too long", type_line+5- buffer); 80 81memcpy(type, type_line+5, typelen); 82 type[typelen] =0; 83 84/* Verify that the object matches */ 85if(verify_object(sha1, type)) 86returnerror("char%d: could not verify object%s",7,sha1_to_hex(sha1)); 87 88/* Verify the tag-name: we don't allow control characters or spaces in it */ 89 tag_line +=4; 90for(;;) { 91unsigned char c = *tag_line++; 92if(c =='\n') 93break; 94if(c >' ') 95continue; 96returnerror("char" PD_FMT ": could not verify tag name", tag_line - buffer); 97} 98 99/* Verify the tagger line */ 100 tagger_line = tag_line; 101 102if(memcmp(tagger_line,"tagger ",7)) 103returnerror("char" PD_FMT ": could not find\"tagger\"", 104 tagger_line - buffer); 105 106/* 107 * Check for correct form for name and email 108 * i.e. " <" followed by "> " on _this_ line 109 * No angle brackets within the name or email address fields. 110 * No spaces within the email address field. 111 */ 112 tagger_line +=7; 113if(!(lb =strstr(tagger_line," <")) || !(rb =strstr(lb+2,"> ")) || 114strpbrk(tagger_line,"<>\n") != lb+1|| 115strpbrk(lb+2,"><\n") != rb) 116returnerror("char" PD_FMT ": malformed tagger field", 117 tagger_line - buffer); 118 119/* Check for author name, at least one character, space is acceptable */ 120if(lb == tagger_line) 121returnerror("char" PD_FMT ": missing tagger name", 122 tagger_line - buffer); 123 124/* timestamp, 1 or more digits followed by space */ 125 tagger_line = rb +2; 126if(!(len =strspn(tagger_line,"0123456789"))) 127returnerror("char" PD_FMT ": missing tag timestamp", 128 tagger_line - buffer); 129 tagger_line += len; 130if(*tagger_line !=' ') 131returnerror("char" PD_FMT ": malformed tag timestamp", 132 tagger_line - buffer); 133 tagger_line++; 134 135/* timezone, 5 digits [+-]hhmm, max. 1400 */ 136if(!((tagger_line[0] =='+'|| tagger_line[0] =='-') && 137strspn(tagger_line+1,"0123456789") ==4&& 138 tagger_line[5] =='\n'&&atoi(tagger_line+1) <=1400)) 139returnerror("char" PD_FMT ": malformed tag timezone", 140 tagger_line - buffer); 141 tagger_line +=6; 142 143/* Verify the blank line separating the header from the body */ 144if(*tagger_line !='\n') 145returnerror("char" PD_FMT ": trailing garbage in tag header", 146 tagger_line - buffer); 147 148/* The actual stuff afterwards we don't care about.. */ 149return0; 150} 151 152#undef PD_FMT 153 154intmain(int argc,char**argv) 155{ 156struct strbuf buf; 157unsigned char result_sha1[20]; 158 159if(argc !=1) 160usage("git-mktag < signaturefile"); 161 162setup_git_directory(); 163 164strbuf_init(&buf,0); 165if(strbuf_read(&buf,0,4096) <0) { 166die("could not read from stdin"); 167} 168 169/* Verify it for some basic sanity: it needs to start with 170 "object <sha1>\ntype\ntagger " */ 171if(verify_tag(buf.buf, buf.len) <0) 172die("invalid tag signature file"); 173 174if(write_sha1_file(buf.buf, buf.len, tag_type, result_sha1) <0) 175die("unable to write tag file"); 176 177strbuf_release(&buf); 178printf("%s\n",sha1_to_hex(result_sha1)); 179return0; 180}