ENGINE-222: checking in this mess so I can figured out why it breaks. gnupg-2.1
authorKrista Bennett <krista@pep-project.org>
Fri, 14 Jul 2017 18:27:42 +0200
branchgnupg-2.1
changeset 1924c40a363fae45
parent 1923 e487588a77dc
child 1925 bee52dae2cb9
ENGINE-222: checking in this mess so I can figured out why it breaks.
src/pgp_gpg.c
src/pgp_gpg.h
     1.1 --- a/src/pgp_gpg.c	Thu Jul 13 15:10:53 2017 +0200
     1.2 +++ b/src/pgp_gpg.c	Fri Jul 14 18:27:42 2017 +0200
     1.3 @@ -1087,23 +1087,42 @@
     1.4          strlcat(userid, identity->address, userid_size);
     1.5          strlcat(userid, ">", userid_size);
     1.6          gpgme_error = gpg.gpgme_op_createkey(session->ctx, userid, "RSA", 
     1.7 -                                             0, 31536000, NULL, GPGME_CREATE_NOPASSWD);
     1.8 +                                             0, 31536000, NULL, 
     1.9 +                                             GPGME_CREATE_NOPASSWD | 
    1.10 +                                             GPGME_CREATE_SIGN |
    1.11 +                                             GPGME_CREATE_ENCR |
    1.12 +                                             GPGME_CREATE_CERT |
    1.13 +                                             GPGME_CREATE_AUTH |
    1.14 +                                             GPGME_CREATE_FORCE);
    1.15          gpgme_error = _GPGERR(gpgme_error);
    1.16  
    1.17          free(userid);
    1.18  
    1.19          if (gpgme_error != GPG_ERR_NOT_SUPPORTED) {
    1.20              switch (gpgme_error) {
    1.21 -            case GPG_ERR_NO_ERROR:
    1.22 -                return PEP_STATUS_OK;		    
    1.23 -            case GPG_ERR_INV_VALUE:
    1.24 -                return PEP_ILLEGAL_VALUE;
    1.25 -            case GPG_ERR_GENERAL:
    1.26 -                return PEP_CANNOT_CREATE_KEY;
    1.27 -            default:
    1.28 -                assert(0);
    1.29 -                return PEP_UNKNOWN_ERROR;
    1.30 +                case GPG_ERR_NO_ERROR:
    1.31 +                    break;		    
    1.32 +                case GPG_ERR_INV_VALUE:
    1.33 +                    return PEP_ILLEGAL_VALUE;
    1.34 +                case GPG_ERR_GENERAL:
    1.35 +                    return PEP_CANNOT_CREATE_KEY;
    1.36 +                default:
    1.37 +                    assert(0);
    1.38 +                    return PEP_UNKNOWN_ERROR;
    1.39              }        
    1.40 +
    1.41 +            /* This is the same regardless of whether we got it from genkey or createkey */
    1.42 +            gpgme_genkey_result_t gpgme_genkey_result = gpg.gpgme_op_genkey_result(session->ctx);
    1.43 +            assert(gpgme_genkey_result);
    1.44 +            assert(gpgme_genkey_result->fpr);
    1.45 +
    1.46 +            free(identity->fpr);
    1.47 +            identity->fpr = strdup(gpgme_genkey_result->fpr);
    1.48 +            if (identity->fpr == NULL)
    1.49 +                return PEP_OUT_OF_MEMORY;
    1.50 +
    1.51 +            status = pgp_replace_only_uid(session, identity->fpr,
    1.52 +                        identity->username, identity->address);                        
    1.53          }
    1.54  #endif
    1.55  #endif
    1.56 @@ -1124,57 +1143,53 @@
    1.57  
    1.58      PEP_STATUS status = _pgp_createkey(session, identity);
    1.59      
    1.60 -    if (status != PEP_STATUS_OK && 
    1.61 -        status != PEP_VERSION_MISMATCH)
    1.62 +    if (status != PEP_VERSION_MISMATCH)
    1.63          return status;
    1.64 +        
    1.65 +    gpgme_error_t gpgme_error;
    1.66 +    char *parms;
    1.67 +    const char *template =
    1.68 +        "<GnupgKeyParms format=\"internal\">\n"
    1.69 +        "Key-Type: RSA\n"
    1.70 +        "Key-Length: 4096\n"
    1.71 +        "Subkey-Type: RSA\n"
    1.72 +        "Subkey-Length: 4096\n"
    1.73 +        "Name-Real: %s\n"
    1.74 +        "Name-Email: %s\n"
    1.75 +        /* "Passphrase: %s\n" */
    1.76 +        "Expire-Date: 1y\n"
    1.77 +        "</GnupgKeyParms>\n";
    1.78 +    int result;
    1.79  
    1.80 -    if (status == PEP_VERSION_MISMATCH) {
    1.81 -        gpgme_error_t gpgme_error;
    1.82 -        char *parms;
    1.83 -        const char *template =
    1.84 -            "<GnupgKeyParms format=\"internal\">\n"
    1.85 -            "Key-Type: RSA\n"
    1.86 -            "Key-Length: 4096\n"
    1.87 -            "Subkey-Type: RSA\n"
    1.88 -            "Subkey-Length: 4096\n"
    1.89 -            "Name-Real: %s\n"
    1.90 -            "Name-Email: %s\n"
    1.91 -            /* "Passphrase: %s\n" */
    1.92 -            "Expire-Date: 1y\n"
    1.93 -            "</GnupgKeyParms>\n";
    1.94 -        int result;
    1.95 -    
    1.96 -        parms = calloc(1, PARMS_MAX);
    1.97 -        assert(parms);
    1.98 -        if (parms == NULL)
    1.99 -            return PEP_OUT_OF_MEMORY;
   1.100 +    parms = calloc(1, PARMS_MAX);
   1.101 +    assert(parms);
   1.102 +    if (parms == NULL)
   1.103 +        return PEP_OUT_OF_MEMORY;
   1.104  
   1.105 -        result = snprintf(parms, PARMS_MAX, template, identity->username,
   1.106 -            identity->address); // , session->passphrase);
   1.107 -        assert(result < PARMS_MAX);
   1.108 -        if (result >= PARMS_MAX) {
   1.109 -            free(parms);
   1.110 -            return PEP_BUFFER_TOO_SMALL;
   1.111 -        }
   1.112 -
   1.113 -        gpgme_error = gpg.gpgme_op_genkey(session->ctx, parms, NULL, NULL);
   1.114 -        gpgme_error = _GPGERR(gpgme_error);
   1.115 +    result = snprintf(parms, PARMS_MAX, template, identity->username,
   1.116 +        identity->address); // , session->passphrase);
   1.117 +    assert(result < PARMS_MAX);
   1.118 +    if (result >= PARMS_MAX) {
   1.119          free(parms);
   1.120 -
   1.121 -        switch (gpgme_error) {
   1.122 -        case GPG_ERR_NO_ERROR:
   1.123 -            break;
   1.124 -        case GPG_ERR_INV_VALUE:
   1.125 -            return PEP_ILLEGAL_VALUE;
   1.126 -        case GPG_ERR_GENERAL:
   1.127 -            return PEP_CANNOT_CREATE_KEY;
   1.128 -        default:
   1.129 -            assert(0);
   1.130 -            return PEP_UNKNOWN_ERROR;
   1.131 -        }
   1.132 +        return PEP_BUFFER_TOO_SMALL;
   1.133      }
   1.134  
   1.135 -    /* This is the same regardless of whether we got it from genkey or createkey */
   1.136 +    gpgme_error = gpg.gpgme_op_genkey(session->ctx, parms, NULL, NULL);
   1.137 +    gpgme_error = _GPGERR(gpgme_error);
   1.138 +    free(parms);
   1.139 +
   1.140 +    switch (gpgme_error) {
   1.141 +    case GPG_ERR_NO_ERROR:
   1.142 +        break;
   1.143 +    case GPG_ERR_INV_VALUE:
   1.144 +        return PEP_ILLEGAL_VALUE;
   1.145 +    case GPG_ERR_GENERAL:
   1.146 +        return PEP_CANNOT_CREATE_KEY;
   1.147 +    default:
   1.148 +        assert(0);
   1.149 +        return PEP_UNKNOWN_ERROR;
   1.150 +    }
   1.151 +
   1.152      gpgme_genkey_result_t gpgme_genkey_result = gpg.gpgme_op_genkey_result(session->ctx);
   1.153      assert(gpgme_genkey_result);
   1.154      assert(gpgme_genkey_result->fpr);
   1.155 @@ -1846,6 +1861,290 @@
   1.156      return PEP_STATUS_OK;
   1.157  }
   1.158  
   1.159 +static ssize_t _nullwriter(
   1.160 +        void *_handle,
   1.161 +        const void *buffer,
   1.162 +        size_t size
   1.163 +    )
   1.164 +{
   1.165 +    return size;
   1.166 +}
   1.167 +
   1.168 +typedef struct _replace_only_uid_state {
   1.169 +    enum {
   1.170 +        replace_uid_command = 0,
   1.171 +        replace_uid_realname,
   1.172 +        replace_uid_email,
   1.173 +        replace_uid_adduid_ok,
   1.174 +        replace_uid_select_for_delete,
   1.175 +        replace_uid_delete,
   1.176 +        replace_uid_delete_confirm,
   1.177 +        replace_uid_select_for_trust,
   1.178 +        replace_uid_trust,
   1.179 +        replace_uid_trust_ultimate,
   1.180 +        replace_uid_trust_ultimate_confirm,
   1.181 +        replace_uid_quit,
   1.182 +        replace_uid_save_okay,
   1.183 +        replace_uid_exit,
   1.184 +        replace_uid_error = -1
   1.185 +    } state;
   1.186 +const char *realname;
   1.187 +const char *email;
   1.188 +} replace_only_uid_state;
   1.189 +
   1.190 +static gpgme_error_t replace_only_uid_fsm(
   1.191 +    void *_handle,
   1.192 +    gpgme_status_code_t statuscode,
   1.193 +    const char *args,
   1.194 +    int fd
   1.195 +)
   1.196 +{
   1.197 +    replace_only_uid_state *handle = _handle;
   1.198 +        
   1.199 +    switch (handle->state) {
   1.200 +        case replace_uid_command:
   1.201 +            if (statuscode == GPGME_STATUS_GET_LINE) {
   1.202 +                assert(strcmp(args, "keyedit.prompt") == 0);
   1.203 +                if (strcmp(args, "keyedit.prompt")) {
   1.204 +                    handle->state = replace_uid_error;
   1.205 +                    return GPG_ERR_GENERAL;
   1.206 +                }
   1.207 +                gpg.gpgme_io_write(fd, "adduid\n", 7);
   1.208 +                handle->state = replace_uid_realname;
   1.209 +            }
   1.210 +            break;
   1.211 +            
   1.212 +        case replace_uid_realname:
   1.213 +            if (statuscode == GPGME_STATUS_GET_LINE) {
   1.214 +                assert(strcmp(args, "keygen.name") == 0);
   1.215 +                assert(handle->realname);
   1.216 +                if (strcmp(args, "keygen.name") || !handle->realname) {
   1.217 +                    handle->state = replace_uid_error;
   1.218 +                    return GPG_ERR_GENERAL;
   1.219 +                }
   1.220 +                size_t realname_strlen = strlen(handle->realname);
   1.221 +                char* realname = (char*)calloc(1, realname_strlen + 2); // \n + \0
   1.222 +                if (!realname) {
   1.223 +                    handle->state = replace_uid_error;
   1.224 +                    return GPG_ERR_ENOMEM;
   1.225 +                }
   1.226 +                strlcpy(realname, handle->realname, realname_strlen);
   1.227 +                realname[realname_strlen] = '\n'; 
   1.228 +                gpg.gpgme_io_write(fd, realname, realname_strlen + 1);
   1.229 +                handle->state = replace_uid_email;
   1.230 +                free(realname);
   1.231 +            }
   1.232 +            break;
   1.233 +            
   1.234 +        case replace_uid_email:
   1.235 +            if (statuscode == GPGME_STATUS_GET_LINE) {
   1.236 +                assert(strcmp(args, "keygen.email") == 0);
   1.237 +                assert(handle->email);
   1.238 +                if (strcmp(args, "keygen.email") || !handle->email) {
   1.239 +                    handle->state = replace_uid_error;
   1.240 +                    return GPG_ERR_GENERAL;
   1.241 +                }
   1.242 +                size_t email_strlen = strlen(handle->email);
   1.243 +                char* email = (char*)calloc(1, email_strlen + 2); // \n + \0
   1.244 +                if (!email) {
   1.245 +                    handle->state = replace_uid_error;
   1.246 +                    return GPG_ERR_ENOMEM;
   1.247 +                }
   1.248 +                strlcpy(email, handle->email, email_strlen);
   1.249 +                email[email_strlen] = '\n'; 
   1.250 +                gpg.gpgme_io_write(fd, email, email_strlen + 1);
   1.251 +                handle->state = replace_uid_adduid_ok;
   1.252 +                free(email);
   1.253 +            }
   1.254 +            break;
   1.255 +
   1.256 +        case replace_uid_adduid_ok:
   1.257 +            if (statuscode == GPGME_STATUS_GET_LINE) {
   1.258 +                assert(strcmp(args, "keygen.userid.cmd") == 0);
   1.259 +                assert(handle->email);
   1.260 +                if (strcmp(args, "keygen.userid.cmd")) {
   1.261 +                    handle->state = replace_uid_error;
   1.262 +                    return GPG_ERR_GENERAL;
   1.263 +                }
   1.264 +                gpg.gpgme_io_write(fd, "O\n", 2);
   1.265 +                handle->state = replace_uid_select_for_delete;
   1.266 +            }
   1.267 +            break;
   1.268 +
   1.269 +        case replace_uid_select_for_delete:
   1.270 +            if (statuscode == GPGME_STATUS_GET_LINE) {
   1.271 +                assert(strcmp(args, "keyedit.prompt") == 0);
   1.272 +                assert(handle->email);
   1.273 +                if (strcmp(args, "keyedit.prompt")) {
   1.274 +                    handle->state = replace_uid_error;
   1.275 +                    return GPG_ERR_GENERAL;
   1.276 +                }
   1.277 +                gpg.gpgme_io_write(fd, "uid 1\n", 6);
   1.278 +                handle->state = replace_uid_delete;
   1.279 +            }
   1.280 +            break;
   1.281 +
   1.282 +        case replace_uid_delete:
   1.283 +            if (statuscode == GPGME_STATUS_GET_LINE) {
   1.284 +                assert(strcmp(args, "keyedit.prompt") == 0);
   1.285 +                assert(handle->email);
   1.286 +                if (strcmp(args, "keyedit.prompt")) {
   1.287 +                    handle->state = replace_uid_error;
   1.288 +                    return GPG_ERR_GENERAL;
   1.289 +                }
   1.290 +                gpg.gpgme_io_write(fd, "deluid\n", 7);
   1.291 +                handle->state = replace_uid_delete_confirm;
   1.292 +            }
   1.293 +            break;
   1.294 +
   1.295 +        case replace_uid_delete_confirm:
   1.296 +            if (statuscode == GPGME_STATUS_GET_LINE) {
   1.297 +                assert(strcmp(args, "keyedit.remove.uid.okay") == 0);
   1.298 +                assert(handle->email);
   1.299 +                if (strcmp(args, "keyedit.remove.uid.okay")) {
   1.300 +                    handle->state = replace_uid_error;
   1.301 +                    return GPG_ERR_GENERAL;
   1.302 +                }
   1.303 +                gpg.gpgme_io_write(fd, "Y\n", 2);
   1.304 +                handle->state = replace_uid_select_for_trust;
   1.305 +            }
   1.306 +            break;
   1.307 +
   1.308 +        case replace_uid_select_for_trust:
   1.309 +            if (statuscode == GPGME_STATUS_GET_LINE) {
   1.310 +                assert(strcmp(args, "keyedit.prompt") == 0);
   1.311 +                assert(handle->email);
   1.312 +                if (strcmp(args, "keyedit.prompt")) {
   1.313 +                    handle->state = replace_uid_error;
   1.314 +                    return GPG_ERR_GENERAL;
   1.315 +                }
   1.316 +                gpg.gpgme_io_write(fd, "uid 1\n", 5);
   1.317 +                handle->state = replace_uid_trust;
   1.318 +            }
   1.319 +            break;
   1.320 +
   1.321 +        case replace_uid_trust:
   1.322 +            if (statuscode == GPGME_STATUS_GET_LINE) {
   1.323 +                assert(strcmp(args, "keyedit.prompt") == 0);
   1.324 +                assert(handle->email);
   1.325 +                if (strcmp(args, "keyedit.prompt")) {
   1.326 +                    handle->state = replace_uid_error;
   1.327 +                    return GPG_ERR_GENERAL;
   1.328 +                }
   1.329 +                gpg.gpgme_io_write(fd, "trust\n", 5);
   1.330 +                handle->state = replace_uid_trust_ultimate;
   1.331 +            }
   1.332 +            break;
   1.333 +
   1.334 +        case replace_uid_trust_ultimate:
   1.335 +            if (statuscode == GPGME_STATUS_GET_LINE) {
   1.336 +                assert(strcmp(args, "edit_ownertrust.value") == 0);
   1.337 +                assert(handle->email);
   1.338 +                if (strcmp(args, "edit_ownertrust.value")) {
   1.339 +                    handle->state = replace_uid_error;
   1.340 +                    return GPG_ERR_GENERAL;
   1.341 +                }
   1.342 +                gpg.gpgme_io_write(fd, "5\n", 2);
   1.343 +                handle->state = replace_uid_trust_ultimate_confirm;
   1.344 +            }
   1.345 +            break;
   1.346 +
   1.347 +        case replace_uid_trust_ultimate_confirm:
   1.348 +            if (statuscode == GPGME_STATUS_GET_LINE) {
   1.349 +                assert(strcmp(args, "edit_ownertrust.set_ultimate.okay") == 0);
   1.350 +                assert(handle->email);
   1.351 +                if (strcmp(args, "edit_ownertrust.set_ultimate.okay")) {
   1.352 +                    handle->state = replace_uid_error;
   1.353 +                    return GPG_ERR_GENERAL;
   1.354 +                }
   1.355 +                gpg.gpgme_io_write(fd, "Y\n", 2);
   1.356 +                handle->state = replace_uid_quit;
   1.357 +            }
   1.358 +            break;
   1.359 +
   1.360 +        case replace_uid_quit:
   1.361 +            if (statuscode == GPGME_STATUS_GET_LINE) {
   1.362 +                assert(strcmp(args, "keyedit.prompt") == 0);
   1.363 +                assert(handle->email);
   1.364 +                if (strcmp(args, "keyedit.prompt")) {
   1.365 +                    handle->state = replace_uid_error;
   1.366 +                    return GPG_ERR_GENERAL;
   1.367 +                }
   1.368 +                gpg.gpgme_io_write(fd, "quit\n", 5);
   1.369 +                handle->state = replace_uid_save_okay;
   1.370 +            }
   1.371 +            break;
   1.372 +
   1.373 +        case replace_uid_save_okay:
   1.374 +            if (statuscode == GPGME_STATUS_GET_LINE) {
   1.375 +                assert(strcmp(args, "keyedit.save.okay") == 0);
   1.376 +                assert(handle->email);
   1.377 +                if (strcmp(args, "keyedit.save.okay")) {
   1.378 +                    handle->state = replace_uid_error;
   1.379 +                    return GPG_ERR_GENERAL;
   1.380 +                }
   1.381 +                gpg.gpgme_io_write(fd, "Y\n", 2);
   1.382 +                handle->state = replace_uid_exit;
   1.383 +            }
   1.384 +            break;
   1.385 +
   1.386 +        case replace_uid_exit:
   1.387 +            break;
   1.388 +
   1.389 +        case replace_uid_error:
   1.390 +            return GPG_ERR_GENERAL;
   1.391 +            
   1.392 +        default:
   1.393 +            break;                
   1.394 +    }
   1.395 +    return GPG_ERR_NO_ERROR;
   1.396 +}
   1.397 +
   1.398 +PEP_STATUS pgp_replace_only_uid(
   1.399 +        PEP_SESSION session,
   1.400 +        const char* fpr,
   1.401 +        const char* realname,
   1.402 +        const char* email
   1.403 +    )
   1.404 +{
   1.405 +    PEP_STATUS status = PEP_STATUS_OK;
   1.406 +    gpgme_error_t gpgme_error;
   1.407 +    gpgme_key_t key;
   1.408 +    gpgme_data_t output;
   1.409 +    replace_only_uid_state handle;
   1.410 +
   1.411 +    assert(session);
   1.412 +    assert(fpr);
   1.413 +    assert(realname);
   1.414 +    assert(email);
   1.415 +    
   1.416 +    memset(&handle, 0, sizeof(replace_only_uid_state));
   1.417 +    handle.realname = realname;
   1.418 +    handle.email = email;
   1.419 +
   1.420 +    status = find_single_key(session, fpr, &key);
   1.421 +    if (status != PEP_STATUS_OK)
   1.422 +        return status;
   1.423 +
   1.424 +    struct gpgme_data_cbs data_cbs;
   1.425 +    memset(&data_cbs, 0, sizeof(struct gpgme_data_cbs));
   1.426 +    data_cbs.write = _nullwriter;
   1.427 +    gpg.gpgme_data_new_from_cbs(&output, &data_cbs, &handle);
   1.428 +
   1.429 +    gpgme_error = gpg.gpgme_op_edit(session->ctx, key, replace_only_uid_fsm, &handle,
   1.430 +            output);
   1.431 +    assert(gpgme_error == GPG_ERR_NO_ERROR);
   1.432 +    if(gpgme_error != GPG_ERR_NO_ERROR) {
   1.433 +        status = PEP_CANNOT_EDIT_KEY;
   1.434 +    }
   1.435 +
   1.436 +    gpg.gpgme_data_release(output);
   1.437 +    gpg.gpgme_key_unref(key);
   1.438 +
   1.439 +    return status;
   1.440 +}
   1.441 +
   1.442 +
   1.443  typedef struct _renew_state {
   1.444      enum {
   1.445          renew_command = 0,
   1.446 @@ -1965,14 +2264,6 @@
   1.447      return GPG_ERR_NO_ERROR;
   1.448  }
   1.449  
   1.450 -static ssize_t _nullwriter(
   1.451 -        void *_handle,
   1.452 -        const void *buffer,
   1.453 -        size_t size
   1.454 -    )
   1.455 -{
   1.456 -    return size;
   1.457 -}
   1.458  
   1.459  PEP_STATUS pgp_renew_key(
   1.460          PEP_SESSION session,
     2.1 --- a/src/pgp_gpg.h	Thu Jul 13 15:10:53 2017 +0200
     2.2 +++ b/src/pgp_gpg.h	Fri Jul 14 18:27:42 2017 +0200
     2.3 @@ -105,4 +105,14 @@
     2.4  );
     2.5  
     2.6  PEP_STATUS pgp_binary(const char **path);
     2.7 +
     2.8 +/* Really only internal. */
     2.9 +PEP_STATUS pgp_replace_only_uid(
    2.10 +        PEP_SESSION session,
    2.11 +        const char* fpr,
    2.12 +        const char* realname,
    2.13 +        const char* email
    2.14 +    );
    2.15 +
    2.16 +
    2.17  #define PGP_BINARY_PATH pgp_binary