| | 127 | static gboolean ssl_starttls_real( gpointer data, gint source, b_input_condition cond ) |
| | 128 | { |
| | 129 | struct scd *conn = data; |
| | 130 | |
| | 131 | return ssl_connected( conn, conn->fd, B_EV_IO_WRITE ); |
| | 132 | } |
| | 133 | |
| | 134 | void *ssl_starttls( int fd, ssl_input_function func, gpointer data ) |
| | 135 | { |
| | 136 | struct scd *conn = g_new0( struct scd, 1 ); |
| | 137 | |
| | 138 | conn->fd = fd; |
| | 139 | conn->func = func; |
| | 140 | conn->data = data; |
| | 141 | |
| | 142 | /* This function should be called via a (short) timeout instead of |
| | 143 | directly from here, because these SSL calls are *supposed* to be |
| | 144 | *completely* asynchronous and not ready yet when this function |
| | 145 | (or *_connect, for examle) returns. Also, errors are reported via |
| | 146 | the callback function, not via this function's return value. |
| | 147 | |
| | 148 | In short, doing things like this makes the rest of the code a lot |
| | 149 | simpler. */ |
| | 150 | |
| | 151 | b_timeout_add( 1, ssl_starttls_real, conn ); |
| | 152 | |
| | 153 | return conn; |
| | 154 | } |
| | 155 | |
| | 235 | |
| | 236 | size_t ssl_des3_encrypt(const unsigned char *key, size_t key_len, |
| | 237 | const unsigned char *input, size_t input_len, const unsigned char *iv, |
| | 238 | unsigned char **res) |
| | 239 | { |
| | 240 | int output_length = 0; |
| | 241 | |
| | 242 | CK_MECHANISM_TYPE cipherMech; |
| | 243 | PK11SlotInfo* slot = NULL; |
| | 244 | PK11SymKey* SymKey = NULL; |
| | 245 | SECItem* SecParam = NULL; |
| | 246 | PK11Context* EncContext = NULL; |
| | 247 | SECItem keyItem, ivItem; |
| | 248 | SECStatus rv1, rv2; |
| | 249 | int tmp1_outlen, tmp2_outlen; |
| | 250 | |
| | 251 | if (!initialized) |
| | 252 | { |
| | 253 | ssl_init(); |
| | 254 | } |
| | 255 | |
| | 256 | *res = g_new0(unsigned char, 1024); |
| | 257 | |
| | 258 | cipherMech = CKM_DES3_CBC_PAD; |
| | 259 | slot = PK11_GetBestSlot(cipherMech, NULL); |
| | 260 | |
| | 261 | if (slot == NULL) |
| | 262 | { |
| | 263 | fprintf(stderr, "Unable to find security device (err %d)\n", |
| | 264 | PR_GetError()); |
| | 265 | goto out; |
| | 266 | } |
| | 267 | |
| | 268 | // Converts "raw key" into a key object. |
| | 269 | keyItem.type = siBuffer; |
| | 270 | keyItem.data = (unsigned char*)key; |
| | 271 | keyItem.len = key_len; |
| | 272 | |
| | 273 | SymKey = PK11_ImportSymKey(slot, cipherMech, PK11_OriginUnwrap, CKA_ENCRYPT, |
| | 274 | &keyItem, NULL); |
| | 275 | |
| | 276 | if (SymKey == NULL) |
| | 277 | { |
| | 278 | fprintf(stderr, "Failure to import key into NSS (err %d)\n", |
| | 279 | PR_GetError()); |
| | 280 | goto out; |
| | 281 | } |
| | 282 | |
| | 283 | /* set up the PKCS11 encryption paramters. |
| | 284 | * when not using CBC mode, ivItem.data and ivItem.len can be 0, or you |
| | 285 | * can simply pass NULL for the iv parameter in PK11_ParamFromIV func |
| | 286 | */ |
| | 287 | ivItem.type = siBuffer; |
| | 288 | ivItem.data = iv; |
| | 289 | ivItem.len = strlen(iv); // ??? Is it right? FIXME |
| | 290 | SecParam = PK11_ParamFromIV(cipherMech, &ivItem); |
| | 291 | if (SecParam == NULL) |
| | 292 | { |
| | 293 | fprintf(stderr, "Failure to set up PKCS11 param (err %d)\n", |
| | 294 | PR_GetError()); |
| | 295 | goto out; |
| | 296 | } |
| | 297 | |
| | 298 | /* ========================= START SECTION ============================= */ |
| | 299 | /* If using the the same key and iv over and over, stuff before this */ |
| | 300 | /* section and after this section needs to be done only ONCE */ |
| | 301 | /* ENCRYPT data into buf1. buf1 len must be atleast (data len + 8) */ |
| | 302 | tmp1_outlen = tmp2_outlen = 0; |
| | 303 | |
| | 304 | /* Create cipher context */ |
| | 305 | EncContext = PK11_CreateContextBySymKey(cipherMech, CKA_ENCRYPT, |
| | 306 | SymKey, SecParam); |
| | 307 | rv1 = PK11_CipherOp(EncContext, res, &tmp1_outlen, sizeof(res), |
| | 308 | input, input_len+1); |
| | 309 | rv2 = PK11_DigestFinal(EncContext, res+tmp1_outlen, &tmp2_outlen, |
| | 310 | sizeof(res)-tmp1_outlen); |
| | 311 | PK11_DestroyContext(EncContext, PR_TRUE); |
| | 312 | output_length = tmp1_outlen + tmp2_outlen; |
| | 313 | if (rv1 != SECSuccess || rv2 != SECSuccess) |
| | 314 | goto out; |
| | 315 | |
| | 316 | return output_length; |
| | 317 | |
| | 318 | out: |
| | 319 | if (SymKey) |
| | 320 | PK11_FreeSymKey(SymKey); |
| | 321 | if (SecParam) |
| | 322 | SECITEM_FreeItem(SecParam, PR_TRUE); |
| | 323 | } |