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