Merging in ENGINE-215
authorKrista Bennett <krista@pep-project.org>
Thu, 15 Jun 2017 18:49:12 +0200
changeset 1866cc57e29989a4
parent 1863 c9c47bbd0dcd
parent 1865 6e6773656dff
child 1868 a3bf01e38752
child 1869 9f79dec887af
child 1870 4334908a5f9f
Merging in ENGINE-215
     1.1 --- a/src/message_api.c	Thu Jun 15 15:32:43 2017 +0200
     1.2 +++ b/src/message_api.c	Thu Jun 15 18:49:12 2017 +0200
     1.3 @@ -2304,6 +2304,74 @@
     1.4      return PEP_color_no_color;
     1.5  }
     1.6  
     1.7 +/* [0-9]: 0x30 - 0x39; [A-F] = 0x41 - 0x46; [a-f] = 0x61 - 0x66 */
     1.8 +static short asciihex_to_num(char a) {
     1.9 +    short conv_num = -1;
    1.10 +    if (a >= 0x30 && a <= 0x39)
    1.11 +        conv_num = a - 0x30;
    1.12 +    else {
    1.13 +        // convert case, subtract offset, get number
    1.14 +        conv_num = ((a | 0x20) - 0x61) + 10;
    1.15 +        if (conv_num < 0xa || conv_num > 0xf)
    1.16 +            conv_num = -1;
    1.17 +    }
    1.18 +    return conv_num;
    1.19 +}
    1.20 +
    1.21 +static char num_to_asciihex(short h) {
    1.22 +    if (h < 0 || h > 16)
    1.23 +        return '\0';
    1.24 +    if (h < 10)
    1.25 +        return (char)(h + 0x30);
    1.26 +    return (char)((h - 10) + 0x41); // for readability
    1.27 +}
    1.28 +
    1.29 +static char xor_hex_chars(char a, char b) {
    1.30 +    short a_num = asciihex_to_num(a);
    1.31 +    short b_num = asciihex_to_num(b);
    1.32 +    if (a_num < 0 || b_num < 0)
    1.33 +        return '\0';
    1.34 +    short xor_num = a_num^b_num;
    1.35 +    return num_to_asciihex(xor_num);
    1.36 +}
    1.37 +
    1.38 +static char* skip_separators(char* current, char* begin) {
    1.39 +    while (current >= begin) {
    1.40 +        /* .:,;-_ ' ' - [2c-2e] [3a-3b] [20] [5f] */
    1.41 +        char check_char = *current;
    1.42 +        switch (check_char) {
    1.43 +            case '.':
    1.44 +            case ':':
    1.45 +            case ',':
    1.46 +            case ';':
    1.47 +            case '-':
    1.48 +            case '_':
    1.49 +            case ' ':
    1.50 +                current--;
    1.51 +                continue;
    1.52 +            default:
    1.53 +                break;
    1.54 +        }
    1.55 +        break;
    1.56 +    }
    1.57 +    return current;
    1.58 +}
    1.59 +
    1.60 +PEP_STATUS check_for_zero_fpr(char* fpr) {
    1.61 +    PEP_STATUS status = PEP_TRUSTWORDS_DUPLICATE_FPR;
    1.62 +    
    1.63 +    while (*fpr) {
    1.64 +        if (*fpr != '0') {
    1.65 +            status = PEP_STATUS_OK;
    1.66 +            break;
    1.67 +        }
    1.68 +        fpr++;    
    1.69 +    }
    1.70 +    
    1.71 +    return status;
    1.72 +    
    1.73 +}
    1.74 +
    1.75  DYNAMIC_API PEP_STATUS get_trustwords(
    1.76      PEP_SESSION session, const pEp_identity* id1, const pEp_identity* id2,
    1.77      const char* lang, char **words, size_t *wsize, bool full
    1.78 @@ -2317,95 +2385,113 @@
    1.79      assert(words);
    1.80      assert(wsize);
    1.81  
    1.82 +    int SHORT_NUM_TWORDS = 5; 
    1.83 +    
    1.84 +    PEP_STATUS status = PEP_STATUS_OK;
    1.85 +    
    1.86      if (!(session && id1 && id2 && words && wsize) ||
    1.87          !(id1->fpr) || (!id2->fpr))
    1.88          return PEP_ILLEGAL_VALUE;
    1.89  
    1.90 -    const char *source1 = id1->fpr;
    1.91 -    const char *source2 = id2->fpr;
    1.92 -
    1.93 -    *words = NULL;
    1.94 +    char *source1 = id1->fpr;
    1.95 +    char *source2 = id2->fpr;
    1.96 +
    1.97 +    int source1_len = strlen(source1);
    1.98 +    int source2_len = strlen(source2);
    1.99 +    int max_len;
   1.100 +        
   1.101 +    *words = NULL;    
   1.102      *wsize = 0;
   1.103  
   1.104 -    const size_t SHORT_NUM_TWORDS = 5;
   1.105 -
   1.106 -    // N.B. THIS will have to be changed once we start checking trustword entropy.
   1.107 -    // For now, full is ALL, and otherwise it's 5-per-id.
   1.108 -    size_t max_words_per_id = (full ? 0 : SHORT_NUM_TWORDS);
   1.109 -
   1.110 -    char* first_set = NULL;
   1.111 -    char* second_set = NULL;
   1.112 -    size_t first_wsize = 0;
   1.113 -    size_t second_wsize = 0;
   1.114 -
   1.115 -    int fpr_comparison = -255;
   1.116 -    PEP_STATUS status = _compare_fprs(source1, strlen(source1), source2, strlen(source2), &fpr_comparison);
   1.117 -    if (status != PEP_STATUS_OK)
   1.118 -        return status;
   1.119 -
   1.120 -    char* _retstr = NULL;
   1.121 -
   1.122 -    switch (fpr_comparison) {
   1.123 -        case 1: // source1 > source2
   1.124 -            status = trustwords(session, source2, lang, &first_set, &first_wsize, max_words_per_id);
   1.125 -            if (status != PEP_STATUS_OK)
   1.126 -                goto error_release;
   1.127 -            status = trustwords(session, source1, lang, &second_set, &second_wsize, max_words_per_id);
   1.128 -            if (status != PEP_STATUS_OK)
   1.129 -                goto error_release;
   1.130 +    max_len = (source1_len > source2_len ? source1_len : source2_len);
   1.131 +    
   1.132 +    char* XORed_fpr = (char*)(calloc(1,max_len + 1));
   1.133 +    *(XORed_fpr + max_len) = '\0';
   1.134 +    char* result_curr = XORed_fpr + max_len - 1;
   1.135 +    char* source1_curr = source1 + source1_len - 1;
   1.136 +    char* source2_curr = source2 + source2_len - 1;
   1.137 +
   1.138 +    while (source1 <= source1_curr && source2 <= source2_curr) {
   1.139 +        source1_curr = skip_separators(source1_curr, source1);
   1.140 +        source2_curr = skip_separators(source2_curr, source2);
   1.141 +        
   1.142 +        if (source1_curr < source1 || source2_curr < source2)
   1.143              break;
   1.144 -        case 0:
   1.145 -        case -1: // source1 <= source2
   1.146 -            status = trustwords(session, source1, lang, &first_set, &first_wsize, max_words_per_id);
   1.147 -            if (status != PEP_STATUS_OK)
   1.148 -                goto error_release;
   1.149 -            status = trustwords(session, source2, lang, &second_set, &second_wsize, max_words_per_id);
   1.150 -            if (status != PEP_STATUS_OK)
   1.151 -                goto error_release;
   1.152 -            break;
   1.153 -        default:
   1.154 -            return ADD_TO_LOG(PEP_UNKNOWN_ERROR); // shouldn't be possible
   1.155 -    }
   1.156 -
   1.157 -    size_t _wsize = first_wsize + second_wsize;
   1.158 -
   1.159 -    bool needs_space = (first_set[first_wsize - 1] != ' ');
   1.160 -
   1.161 -    if (needs_space)
   1.162 -        _wsize++;
   1.163 -
   1.164 -    _retstr = calloc(1, _wsize + 1);
   1.165 -
   1.166 -    size_t len = strlcpy(_retstr, first_set, _wsize);
   1.167 -    if (len >= _wsize) {
   1.168 -        status = PEP_UNKNOWN_ERROR;
   1.169 -        goto error_release;
   1.170 -    }
   1.171 -    if (needs_space) {
   1.172 -        strlcat(_retstr, " ", _wsize);
   1.173 -        if (len >= _wsize) {
   1.174 -            status = PEP_UNKNOWN_ERROR;
   1.175 +            
   1.176 +        char xor_hex = xor_hex_chars(*source1_curr, *source2_curr);
   1.177 +        if (xor_hex == '\0') {
   1.178 +            status = PEP_ILLEGAL_VALUE;
   1.179              goto error_release;
   1.180          }
   1.181 +        
   1.182 +        *result_curr = xor_hex;
   1.183 +        result_curr--; source1_curr--; source2_curr--;
   1.184      }
   1.185 -    strlcat(_retstr, second_set, _wsize);
   1.186 -    if (len >= _wsize){
   1.187 -        status = PEP_UNKNOWN_ERROR;
   1.188 +
   1.189 +    char* remainder_start = NULL;
   1.190 +    char* remainder_curr = NULL;
   1.191 +    
   1.192 +    if (source1 <= source1_curr) {
   1.193 +        remainder_start = source1;
   1.194 +        remainder_curr = source1_curr;
   1.195 +    }
   1.196 +    else if (source2 <= source2_curr) {
   1.197 +        remainder_start = source2;
   1.198 +        remainder_curr = source2_curr;
   1.199 +    }
   1.200 +    if (remainder_curr) {
   1.201 +        while (remainder_start <= remainder_curr) {
   1.202 +            remainder_curr = skip_separators(remainder_curr, remainder_start);
   1.203 +            
   1.204 +            if (remainder_curr < remainder_start)
   1.205 +                break;
   1.206 +            
   1.207 +            char the_char = *remainder_curr;
   1.208 +            
   1.209 +            if (asciihex_to_num(the_char) < 0) {
   1.210 +                status = PEP_ILLEGAL_VALUE;
   1.211 +                goto error_release;
   1.212 +            }
   1.213 +            
   1.214 +            *result_curr = the_char;                
   1.215 +            result_curr--;
   1.216 +            remainder_curr--;
   1.217 +        }
   1.218 +    }
   1.219 +    
   1.220 +    result_curr++;
   1.221 +
   1.222 +    if (result_curr > XORed_fpr) {
   1.223 +        char* tempstr = strdup(result_curr);
   1.224 +        free(XORed_fpr);
   1.225 +        XORed_fpr = tempstr;
   1.226 +    }
   1.227 +    
   1.228 +    status = check_for_zero_fpr(XORed_fpr);
   1.229 +    
   1.230 +    if (status != PEP_STATUS_OK)
   1.231          goto error_release;
   1.232 -    }
   1.233 -
   1.234 -    *words = _retstr;
   1.235 -    *wsize = _wsize;
   1.236 +    
   1.237 +    size_t max_words_per_id = (full ? 0 : SHORT_NUM_TWORDS);
   1.238 +
   1.239 +    char* the_words = NULL;
   1.240 +    size_t the_size = 0;
   1.241 +
   1.242 +    status = trustwords(session, XORed_fpr, lang, &the_words, &the_size, max_words_per_id);
   1.243 +    if (status != PEP_STATUS_OK)
   1.244 +        goto error_release;
   1.245 +
   1.246 +    *words = the_words;
   1.247 +    *wsize = the_size;
   1.248 +    
   1.249      status = PEP_STATUS_OK;
   1.250  
   1.251      goto the_end;
   1.252  
   1.253      error_release:
   1.254 -    free(_retstr);
   1.255 -
   1.256 +        free (XORed_fpr);
   1.257 +        
   1.258      the_end:
   1.259 -    free(first_set);
   1.260 -    free(second_set);
   1.261      return ADD_TO_LOG(status);
   1.262  }
   1.263  
     2.1 --- a/src/pEpEngine.h	Thu Jun 15 15:32:43 2017 +0200
     2.2 +++ b/src/pEpEngine.h	Thu Jun 15 18:49:12 2017 +0200
     2.3 @@ -68,6 +68,7 @@
     2.4  
     2.5      PEP_TRUSTWORD_NOT_FOUND                         = 0x0501,
     2.6      PEP_TRUSTWORDS_FPR_WRONG_LENGTH                 = 0x0502,
     2.7 +    PEP_TRUSTWORDS_DUPLICATE_FPR                    = 0x0503,
     2.8  
     2.9      PEP_CANNOT_CREATE_KEY                           = 0x0601,
    2.10      PEP_CANNOT_SEND_KEY                             = 0x0602,
     3.1 --- a/test/trustwords_test.cc	Thu Jun 15 15:32:43 2017 +0200
     3.2 +++ b/test/trustwords_test.cc	Thu Jun 15 18:49:12 2017 +0200
     3.3 @@ -14,6 +14,7 @@
     3.4      cout << "\n*** get_trustwords test ***\n\n";
     3.5  
     3.6      PEP_SESSION session = nullptr;
     3.7 +    PEP_STATUS status;
     3.8      
     3.9      cout << "calling init()\n";
    3.10      PEP_STATUS status1 = init(&session);
    3.11 @@ -55,29 +56,33 @@
    3.12      assert(words1);
    3.13      cout << words1 << "\n";
    3.14  
    3.15 +    free(words1);
    3.16 +    words1 = nullptr;
    3.17 +    
    3.18      cout << "\nfinding German trustwords for " << fingerprint2 << "...\n";
    3.19      trustwords(session, fingerprint2.c_str(), "de", &words2, &wsize2, 5);
    3.20      assert(words2);
    3.21      cout << words2 << "\n";
    3.22  
    3.23 +    free(words2);
    3.24 +    words1 = nullptr;
    3.25 +
    3.26      cout << "\nfinding German trustwords for " << identity1->address << " and " << identity2->address << "...\n";
    3.27      get_trustwords(session, identity1, identity2, "de", &full_wordlist, &wsize_full, false);
    3.28      assert(full_wordlist);
    3.29      cout << full_wordlist << "\n";
    3.30  
    3.31 -    cout << "\nfinding Englis trustwords for " << identity1->address << " and " << identity2->address << "... with spaces\n";
    3.32 +    free(full_wordlist);
    3.33 +    full_wordlist = nullptr;
    3.34 +
    3.35 +    cout << "\nfinding English trustwords for " << identity1->address << " and " << identity2->address << "... with spaces\n";
    3.36      get_trustwords(session, identity1, identity2_with_spaces, "en", &full_wordlist, &wsize_full, false);
    3.37      assert(full_wordlist);
    3.38      cout << full_wordlist << "\n";
    3.39 +
    3.40 +    free(full_wordlist);
    3.41 +    full_wordlist = nullptr;
    3.42      
    3.43 -    
    3.44 -    pEp_free(words1);
    3.45 -    words1 = nullptr;
    3.46 -    pEp_free(words2);
    3.47 -    words2 = nullptr;
    3.48 -    pEp_free(full_wordlist);
    3.49 -    full_wordlist = nullptr;
    3.50 -
    3.51      cout << "\nTest 2: fpr1 == fpr1, short" << endl;
    3.52      
    3.53      cout << "\nfinding French trustwords for " << fingerprint2 << "...\n";
    3.54 @@ -86,14 +91,14 @@
    3.55      cout << words1 << "\n";
    3.56          
    3.57      cout << "\nfinding French trustwords for " << identity2->address << " and " << identity2->address << "...\n";
    3.58 -    get_trustwords(session, identity2, identity2, "fr", &full_wordlist, &wsize_full, false);
    3.59 -    assert(full_wordlist);
    3.60 -    cout << full_wordlist << "\n";
    3.61 +    status = get_trustwords(session, identity2, identity2, "fr", &full_wordlist, &wsize_full, false);
    3.62 +    assert(status == PEP_TRUSTWORDS_DUPLICATE_FPR);
    3.63 +    cout << "Discovered duplicate fprs as desired" << endl;
    3.64  
    3.65      cout << "\nfinding English trustwords for " << identity2->address << " and " << identity2->address << "... with spaces\n";
    3.66      get_trustwords(session, identity2, identity2_with_spaces, "en", &full_wordlist, &wsize_full, false);
    3.67 -    assert(full_wordlist);
    3.68 -    cout << full_wordlist << "\n";
    3.69 +    assert(status == PEP_TRUSTWORDS_DUPLICATE_FPR);
    3.70 +    cout << "Discovered duplicate fprs as desired" << endl;
    3.71  
    3.72      pEp_free(words1);
    3.73      words1 = nullptr;
    3.74 @@ -112,13 +117,13 @@
    3.75      assert(words2);
    3.76      cout << words2 << "\n";
    3.77      
    3.78 -    cout << "\nfinding English trustwords for " << identity2->address << " and " << identity2->address << "...\n";
    3.79 +    cout << "\nfinding English trustwords for " << identity2->address << " and " << identity1->address << "...\n";
    3.80      get_trustwords(session, identity2, identity1, "en", &full_wordlist, &wsize_full, true);
    3.81      assert(full_wordlist);
    3.82      cout << full_wordlist << "\n";
    3.83      
    3.84 -    cout << "\nfinding English trustwords for " << identity2->address << " and " << identity2->address << "... with spaces\n";
    3.85 -    get_trustwords(session, identity2_with_spaces, identity1, "en", &full_wordlist, &wsize_full, false);
    3.86 +    cout << "\nfinding English trustwords for " << identity2->address << " and " << identity1->address << "... with spaces\n";
    3.87 +    get_trustwords(session, identity2_with_spaces, identity1, "en", &full_wordlist, &wsize_full, true);
    3.88      assert(full_wordlist);
    3.89      cout << full_wordlist << "\n";
    3.90      
    3.91 @@ -199,18 +204,18 @@
    3.92      pEp_free(full_wordlist);
    3.93      full_wordlist = nullptr;
    3.94  
    3.95 -    cout << "\nTest 6: fpr2 is too short" << endl;
    3.96 +    cout << "\nTest 6: fpr2 is shorter" << endl;
    3.97      
    3.98      pEp_identity* identity6 = new_identity(
    3.99          "nobody4@kgrothoff.org",
   3.100 -        "01F932086185C15917B72D30571AFBCA5493553",
   3.101 +        "F1F932086185c15917B72D30571AFBCA5493553",
   3.102          "blargh",
   3.103          "Krista Grothoff");
   3.104      
   3.105      cout << "\nfinding Turkish trustwords for " << identity5->address << " and " << identity6->address << "...\n";
   3.106      PEP_STATUS status6 = get_trustwords(session, identity5, identity6, "tr", &full_wordlist, &wsize_full, false);
   3.107 -    assert(status6 == PEP_TRUSTWORDS_FPR_WRONG_LENGTH);
   3.108 -    cout << "Bad fpr length correctly recognised." << "\n";
   3.109 +    assert(status6 == PEP_STATUS_OK);
   3.110 +    cout << full_wordlist << endl;
   3.111      
   3.112      pEp_identity* identity7 = new_identity(
   3.113          "nobody5@kgrothoff.org",
   3.114 @@ -238,4 +243,3 @@
   3.115      release(session);
   3.116      return 0;
   3.117  }
   3.118 -