Fossil SCM

Added a 'cert' subcommand to manage certificate groups, and added a certificate table to the global db. Minor code formatting change.

jan 2011-03-30 15:40 UTC jan-clientcert
Commit 1156ad25dbb67cefd5c8c5bb244edb3e620ad551
2 files changed +184 -2 +7
+184 -2
--- src/http_ssl.c
+++ src/http_ssl.c
@@ -358,12 +358,11 @@
358358
/*
359359
** Get SSL authentication file reference from environment variable. If set,
360360
** then store varaible in global config. If environment variable was not set,
361361
** attempt to get variable from global config.
362362
**/
363
-char *ssl_get_and_set_file_ref(const char *envvar, const char *dbvar)
364
-{
363
+char *ssl_get_and_set_file_ref(const char *envvar, const char *dbvar){
365364
char *zVar;
366365
char *zTmp;
367366
368367
zTmp = mprintf("%s:%s", dbvar, g.urlName);
369368
@@ -379,7 +378,190 @@
379378
}
380379
free(zTmp);
381380
382381
return zVar;
383382
}
383
+
384
+/*
385
+** COMMAND: cert
386
+**
387
+** Usage: %fossil cert SUBCOMMAND ...
388
+**
389
+** Manage/group PKI keys/certificates to be able to use client
390
+** certificates and register CA certificates for SSL verifications.
391
+**
392
+** %fossil cert add NAME ?--key KEYFILE? ?--cert CERTFILE?
393
+** ?--cafile CAFILE? ?--capath CAPATH?
394
+**
395
+** Create a certificate group NAME with the associated
396
+** certificates/keys. If a client certificate is specified but no
397
+** key, it is assumed that the key is located in the client
398
+** certificate file. The file format must be PEM.
399
+**
400
+** %fossil cert list
401
+**
402
+** List all credential groups, their values and their URL
403
+** associations.
404
+**
405
+** %fossil cert disassociate URL
406
+**
407
+** Disassociate URL from any credential group(s).
408
+**
409
+** %fossil cert delete NAME
410
+**
411
+** Remove the credential group NAME and all it's associated URL
412
+** associations.
413
+*/
414
+void cert_cmd(void){
415
+ int n;
416
+ const char *zCmd = "list";
417
+ if( g.argc>=3 ){
418
+ zCmd = g.argv[2];
419
+ }
420
+ n = strlen(zCmd);
421
+ if( strncmp(zCmd, "add", n)==0 ){
422
+ const char *zContainer;
423
+ const char *zCKey;
424
+ const char *zCCert;
425
+ const char *zCAFile;
426
+ const char *zCAPath;
427
+ if( g.argc<5 ){
428
+ usage("add NAME ?--key CLIENTKEY? ?--cert CLIENTCERT? ?--cafile CAFILE? "
429
+ "?--capath CAPATH?");
430
+ }
431
+ zContainer = g.argv[3];
432
+ zCKey = find_option("key",0,1);
433
+ zCCert = find_option("cert",0,1);
434
+ zCAFile = find_option("cafile",0,1);
435
+ zCAPath = find_option("capath",0,1);
436
+
437
+ /* If a client certificate was specified, but a key was not, assume the
438
+ * key is stored in the same file as the certificate.
439
+ */
440
+ if( !zCKey && zCCert ){
441
+ zCKey = zCCert;
442
+ }
443
+
444
+ db_open_config(0);
445
+ db_swap_connections();
446
+ if( db_exists(
447
+ "SELECT 1 FROM certs"
448
+ " WHERE name='%s'",
449
+ zContainer)!=0 ){
450
+ fossil_fatal("certificate group \"%s\" already exists", zContainer);
451
+ }
452
+ db_begin_transaction();
453
+ if( zCKey ){
454
+ db_multi_exec("INSERT INTO certs (name,type,filepath) "
455
+ "VALUES(%Q,'ckey',%Q)",
456
+ zContainer, zCKey);
457
+ }
458
+ if( zCCert ){
459
+ db_multi_exec("INSERT INTO certs (name,type,filepath) "
460
+ "VALUES(%Q,'ccert',%Q)",
461
+ zContainer, zCCert);
462
+ }
463
+ if( zCAFile ){
464
+ db_multi_exec("INSERT INTO certs (name,type,filepath) "
465
+ "VALUES(%Q,'cafile',%Q)",
466
+ zContainer, zCAFile);
467
+ }
468
+ if( zCAPath ){
469
+ db_multi_exec("INSERT INTO certs (name,type,filepath) "
470
+ "VALUES(%Q,'capath',%Q)",
471
+ zContainer, zCAPath);
472
+ }
473
+ db_end_transaction(0);
474
+ db_swap_connections();
475
+ }else if(strncmp(zCmd, "list", n)==0){
476
+ Stmt q;
477
+ char *grp = NULL;
478
+
479
+ db_open_config(0);
480
+ db_swap_connections();
481
+
482
+ db_prepare(&q, "SELECT name,type,filepath FROM certs"
483
+ " WHERE type NOT IN ('server')"
484
+ " ORDER BY name,type");
485
+ while( db_step(&q)==SQLITE_ROW ){
486
+ const char *zCont = db_column_text(&q, 0);
487
+ const char *zType = db_column_text(&q, 1);
488
+ const char *zFilePath = db_column_text(&q, 2);
489
+ if( fossil_strcmp(zCont, grp)!=0 ){
490
+ free(grp);
491
+ grp = strdup(zCont);
492
+ puts(zCont);
493
+ }
494
+ printf("\t%s=%s\n", zType, zFilePath);
495
+ }
496
+ db_finalize(&q);
497
+
498
+ /* List the URL associations. */
499
+ db_prepare(&q, "SELECT name FROM global_config"
500
+ " WHERE name LIKE 'certgroup:%%' AND value=%Q"
501
+ " ORDER BY name", grp);
502
+ free(grp);
503
+
504
+ while( db_step(&q)==SQLITE_ROW ){
505
+ const char *zName = db_column_text(&q, 0);
506
+ static int first = 1;
507
+ if( first ) {
508
+ puts("\tAssociations");
509
+ first = 0;
510
+ }
511
+ printf("\t\t%s\n", zName+10);
512
+ }
513
+
514
+ db_swap_connections();
515
+ }else if(strncmp(zCmd, "disassociate", n)==0){
516
+ const char *zURL;
517
+ if( g.argc<4 ){
518
+ usage("disassociate URL");
519
+ }
520
+ zURL = g.argv[3];
521
+
522
+ db_open_config(0);
523
+ db_swap_connections();
524
+ db_begin_transaction();
525
+
526
+ db_multi_exec("DELETE FROM global_config WHERE name='certgroup:%s'",
527
+ zURL);
528
+ if( db_changes() == 0 ){
529
+ fossil_warning("No certificate group associated with URL \"%s\".",
530
+ zURL);
531
+ }else{
532
+ printf("%s disassociated from its certificate group.\n", zURL);
533
+ }
534
+ db_end_transaction(0);
535
+ db_swap_connections();
536
+
537
+ }else if(strncmp(zCmd, "delete", n)==0){
538
+ const char *zContainer;
539
+ if( g.argc<4 ){
540
+ usage("delete NAME");
541
+ }
542
+ zContainer = g.argv[3];
543
+
544
+ db_open_config(0);
545
+ db_swap_connections();
546
+ db_begin_transaction();
547
+ db_multi_exec("DELETE FROM certs WHERE name=%Q", zContainer);
548
+ if( db_changes() == 0 ){
549
+ fossil_warning("No certificate group named \"%s\" found",
550
+ zContainer);
551
+ }else{
552
+ printf("%d entries removed\n", db_changes());
553
+ }
554
+ db_multi_exec("DELETE FROM global_config WHERE name LIKE 'certgroup:%%'"
555
+ " AND value=%Q", zContainer);
556
+ if( db_changes() > 0 ){
557
+ printf("%d associations removed\n", db_changes());
558
+ }
559
+ db_end_transaction(0);
560
+ db_swap_connections();
561
+ }else{
562
+ fossil_panic("cert subcommand should be one of: "
563
+ "add list disassociate delete");
564
+ }
565
+}
384566
385567
#endif /* FOSSIL_ENABLE_SSL */
386568
--- src/http_ssl.c
+++ src/http_ssl.c
@@ -358,12 +358,11 @@
358 /*
359 ** Get SSL authentication file reference from environment variable. If set,
360 ** then store varaible in global config. If environment variable was not set,
361 ** attempt to get variable from global config.
362 **/
363 char *ssl_get_and_set_file_ref(const char *envvar, const char *dbvar)
364 {
365 char *zVar;
366 char *zTmp;
367
368 zTmp = mprintf("%s:%s", dbvar, g.urlName);
369
@@ -379,7 +378,190 @@
379 }
380 free(zTmp);
381
382 return zVar;
383 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
384
385 #endif /* FOSSIL_ENABLE_SSL */
386
--- src/http_ssl.c
+++ src/http_ssl.c
@@ -358,12 +358,11 @@
358 /*
359 ** Get SSL authentication file reference from environment variable. If set,
360 ** then store varaible in global config. If environment variable was not set,
361 ** attempt to get variable from global config.
362 **/
363 char *ssl_get_and_set_file_ref(const char *envvar, const char *dbvar){
 
364 char *zVar;
365 char *zTmp;
366
367 zTmp = mprintf("%s:%s", dbvar, g.urlName);
368
@@ -379,7 +378,190 @@
378 }
379 free(zTmp);
380
381 return zVar;
382 }
383
384 /*
385 ** COMMAND: cert
386 **
387 ** Usage: %fossil cert SUBCOMMAND ...
388 **
389 ** Manage/group PKI keys/certificates to be able to use client
390 ** certificates and register CA certificates for SSL verifications.
391 **
392 ** %fossil cert add NAME ?--key KEYFILE? ?--cert CERTFILE?
393 ** ?--cafile CAFILE? ?--capath CAPATH?
394 **
395 ** Create a certificate group NAME with the associated
396 ** certificates/keys. If a client certificate is specified but no
397 ** key, it is assumed that the key is located in the client
398 ** certificate file. The file format must be PEM.
399 **
400 ** %fossil cert list
401 **
402 ** List all credential groups, their values and their URL
403 ** associations.
404 **
405 ** %fossil cert disassociate URL
406 **
407 ** Disassociate URL from any credential group(s).
408 **
409 ** %fossil cert delete NAME
410 **
411 ** Remove the credential group NAME and all it's associated URL
412 ** associations.
413 */
414 void cert_cmd(void){
415 int n;
416 const char *zCmd = "list";
417 if( g.argc>=3 ){
418 zCmd = g.argv[2];
419 }
420 n = strlen(zCmd);
421 if( strncmp(zCmd, "add", n)==0 ){
422 const char *zContainer;
423 const char *zCKey;
424 const char *zCCert;
425 const char *zCAFile;
426 const char *zCAPath;
427 if( g.argc<5 ){
428 usage("add NAME ?--key CLIENTKEY? ?--cert CLIENTCERT? ?--cafile CAFILE? "
429 "?--capath CAPATH?");
430 }
431 zContainer = g.argv[3];
432 zCKey = find_option("key",0,1);
433 zCCert = find_option("cert",0,1);
434 zCAFile = find_option("cafile",0,1);
435 zCAPath = find_option("capath",0,1);
436
437 /* If a client certificate was specified, but a key was not, assume the
438 * key is stored in the same file as the certificate.
439 */
440 if( !zCKey && zCCert ){
441 zCKey = zCCert;
442 }
443
444 db_open_config(0);
445 db_swap_connections();
446 if( db_exists(
447 "SELECT 1 FROM certs"
448 " WHERE name='%s'",
449 zContainer)!=0 ){
450 fossil_fatal("certificate group \"%s\" already exists", zContainer);
451 }
452 db_begin_transaction();
453 if( zCKey ){
454 db_multi_exec("INSERT INTO certs (name,type,filepath) "
455 "VALUES(%Q,'ckey',%Q)",
456 zContainer, zCKey);
457 }
458 if( zCCert ){
459 db_multi_exec("INSERT INTO certs (name,type,filepath) "
460 "VALUES(%Q,'ccert',%Q)",
461 zContainer, zCCert);
462 }
463 if( zCAFile ){
464 db_multi_exec("INSERT INTO certs (name,type,filepath) "
465 "VALUES(%Q,'cafile',%Q)",
466 zContainer, zCAFile);
467 }
468 if( zCAPath ){
469 db_multi_exec("INSERT INTO certs (name,type,filepath) "
470 "VALUES(%Q,'capath',%Q)",
471 zContainer, zCAPath);
472 }
473 db_end_transaction(0);
474 db_swap_connections();
475 }else if(strncmp(zCmd, "list", n)==0){
476 Stmt q;
477 char *grp = NULL;
478
479 db_open_config(0);
480 db_swap_connections();
481
482 db_prepare(&q, "SELECT name,type,filepath FROM certs"
483 " WHERE type NOT IN ('server')"
484 " ORDER BY name,type");
485 while( db_step(&q)==SQLITE_ROW ){
486 const char *zCont = db_column_text(&q, 0);
487 const char *zType = db_column_text(&q, 1);
488 const char *zFilePath = db_column_text(&q, 2);
489 if( fossil_strcmp(zCont, grp)!=0 ){
490 free(grp);
491 grp = strdup(zCont);
492 puts(zCont);
493 }
494 printf("\t%s=%s\n", zType, zFilePath);
495 }
496 db_finalize(&q);
497
498 /* List the URL associations. */
499 db_prepare(&q, "SELECT name FROM global_config"
500 " WHERE name LIKE 'certgroup:%%' AND value=%Q"
501 " ORDER BY name", grp);
502 free(grp);
503
504 while( db_step(&q)==SQLITE_ROW ){
505 const char *zName = db_column_text(&q, 0);
506 static int first = 1;
507 if( first ) {
508 puts("\tAssociations");
509 first = 0;
510 }
511 printf("\t\t%s\n", zName+10);
512 }
513
514 db_swap_connections();
515 }else if(strncmp(zCmd, "disassociate", n)==0){
516 const char *zURL;
517 if( g.argc<4 ){
518 usage("disassociate URL");
519 }
520 zURL = g.argv[3];
521
522 db_open_config(0);
523 db_swap_connections();
524 db_begin_transaction();
525
526 db_multi_exec("DELETE FROM global_config WHERE name='certgroup:%s'",
527 zURL);
528 if( db_changes() == 0 ){
529 fossil_warning("No certificate group associated with URL \"%s\".",
530 zURL);
531 }else{
532 printf("%s disassociated from its certificate group.\n", zURL);
533 }
534 db_end_transaction(0);
535 db_swap_connections();
536
537 }else if(strncmp(zCmd, "delete", n)==0){
538 const char *zContainer;
539 if( g.argc<4 ){
540 usage("delete NAME");
541 }
542 zContainer = g.argv[3];
543
544 db_open_config(0);
545 db_swap_connections();
546 db_begin_transaction();
547 db_multi_exec("DELETE FROM certs WHERE name=%Q", zContainer);
548 if( db_changes() == 0 ){
549 fossil_warning("No certificate group named \"%s\" found",
550 zContainer);
551 }else{
552 printf("%d entries removed\n", db_changes());
553 }
554 db_multi_exec("DELETE FROM global_config WHERE name LIKE 'certgroup:%%'"
555 " AND value=%Q", zContainer);
556 if( db_changes() > 0 ){
557 printf("%d associations removed\n", db_changes());
558 }
559 db_end_transaction(0);
560 db_swap_connections();
561 }else{
562 fossil_panic("cert subcommand should be one of: "
563 "add list disassociate delete");
564 }
565 }
566
567 #endif /* FOSSIL_ENABLE_SSL */
568
--- src/schema.c
+++ src/schema.c
@@ -29,10 +29,17 @@
2929
@ --
3030
@ CREATE TABLE global_config(
3131
@ name TEXT PRIMARY KEY,
3232
@ value TEXT
3333
@ );
34
+@ CREATE TABLE certs(
35
+@ name TEXT NOT NULL,
36
+@ type TEXT NOT NULL,
37
+@ filepath TEXT NOT NULL,
38
+@ PRIMARY KEY(name, type),
39
+@ UNIQUE(name, type)
40
+@ );
3441
;
3542
3643
#if INTERFACE
3744
/*
3845
** The content tables have a content version number which rarely
3946
--- src/schema.c
+++ src/schema.c
@@ -29,10 +29,17 @@
29 @ --
30 @ CREATE TABLE global_config(
31 @ name TEXT PRIMARY KEY,
32 @ value TEXT
33 @ );
 
 
 
 
 
 
 
34 ;
35
36 #if INTERFACE
37 /*
38 ** The content tables have a content version number which rarely
39
--- src/schema.c
+++ src/schema.c
@@ -29,10 +29,17 @@
29 @ --
30 @ CREATE TABLE global_config(
31 @ name TEXT PRIMARY KEY,
32 @ value TEXT
33 @ );
34 @ CREATE TABLE certs(
35 @ name TEXT NOT NULL,
36 @ type TEXT NOT NULL,
37 @ filepath TEXT NOT NULL,
38 @ PRIMARY KEY(name, type),
39 @ UNIQUE(name, type)
40 @ );
41 ;
42
43 #if INTERFACE
44 /*
45 ** The content tables have a content version number which rarely
46

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button