Hex Artifact Content

Artifact f70b629bc8300b7a33fa6acdad350f5f97353588:


0000: 23 21 20 2f 75 73 72 2f 62 69 6e 2f 65 6e 76 20  #! /usr/bin/env 
0010: 74 63 6c 73 68 0a 0a 23 20 43 6f 70 79 72 69 67  tclsh..# Copyrig
0020: 68 74 20 28 63 29 20 32 30 31 36 2c 20 52 6f 79  ht (c) 2016, Roy
0030: 20 4b 65 65 6e 65 0a 23 20 41 6c 6c 20 72 69 67   Keene.# All rig
0040: 68 74 73 20 72 65 73 65 72 76 65 64 2e 0a 23 20  hts reserved..# 
0050: 0a 23 20 52 65 64 69 73 74 72 69 62 75 74 69 6f  .# Redistributio
0060: 6e 20 61 6e 64 20 75 73 65 20 69 6e 20 73 6f 75  n and use in sou
0070: 72 63 65 20 61 6e 64 20 62 69 6e 61 72 79 20 66  rce and binary f
0080: 6f 72 6d 73 2c 20 77 69 74 68 20 6f 72 20 77 69  orms, with or wi
0090: 74 68 6f 75 74 0a 23 20 6d 6f 64 69 66 69 63 61  thout.# modifica
00a0: 74 69 6f 6e 2c 20 61 72 65 20 70 65 72 6d 69 74  tion, are permit
00b0: 74 65 64 20 70 72 6f 76 69 64 65 64 20 74 68 61  ted provided tha
00c0: 74 20 74 68 65 20 66 6f 6c 6c 6f 77 69 6e 67 20  t the following 
00d0: 63 6f 6e 64 69 74 69 6f 6e 73 20 61 72 65 0a 23  conditions are.#
00e0: 20 6d 65 74 3a 0a 23 20 20 20 20 20 20 20 20 20   met:.#         
00f0: 31 2e 20 52 65 64 69 73 74 72 69 62 75 74 69 6f  1. Redistributio
0100: 6e 73 20 6f 66 20 73 6f 75 72 63 65 20 63 6f 64  ns of source cod
0110: 65 20 6d 75 73 74 20 72 65 74 61 69 6e 20 74 68  e must retain th
0120: 65 20 61 62 6f 76 65 20 63 6f 70 79 72 69 67 68  e above copyrigh
0130: 74 0a 23 20 20 20 20 20 20 20 20 20 20 20 20 6e  t.#            n
0140: 6f 74 69 63 65 2c 20 74 68 69 73 20 6c 69 73 74  otice, this list
0150: 20 6f 66 20 63 6f 6e 64 69 74 69 6f 6e 73 20 61   of conditions a
0160: 6e 64 20 74 68 65 20 66 6f 6c 6c 6f 77 69 6e 67  nd the following
0170: 20 64 69 73 63 6c 61 69 6d 65 72 2e 0a 23 20 0a   disclaimer..# .
0180: 23 20 20 20 20 20 20 20 20 20 32 2e 20 52 65 64  #         2. Red
0190: 69 73 74 72 69 62 75 74 69 6f 6e 73 20 69 6e 20  istributions in 
01a0: 62 69 6e 61 72 79 20 66 6f 72 6d 20 6d 75 73 74  binary form must
01b0: 20 72 65 70 72 6f 64 75 63 65 20 74 68 65 20 61   reproduce the a
01c0: 62 6f 76 65 0a 23 20 20 20 20 20 20 20 20 20 20  bove.#          
01d0: 20 20 63 6f 70 79 72 69 67 68 74 20 6e 6f 74 69    copyright noti
01e0: 63 65 2c 20 74 68 69 73 20 6c 69 73 74 20 6f 66  ce, this list of
01f0: 20 63 6f 6e 64 69 74 69 6f 6e 73 20 61 6e 64 20   conditions and 
0200: 74 68 65 20 66 6f 6c 6c 6f 77 69 6e 67 0a 23 20  the following.# 
0210: 20 20 20 20 20 20 20 20 20 20 20 64 69 73 63 6c             discl
0220: 61 69 6d 65 72 20 69 6e 20 74 68 65 20 64 6f 63  aimer in the doc
0230: 75 6d 65 6e 74 61 74 69 6f 6e 20 61 6e 64 2f 6f  umentation and/o
0240: 72 20 6f 74 68 65 72 20 6d 61 74 65 72 69 61 6c  r other material
0250: 73 0a 23 20 20 20 20 20 20 20 20 20 20 20 20 70  s.#            p
0260: 72 6f 76 69 64 65 64 20 77 69 74 68 20 74 68 65  rovided with the
0270: 20 64 69 73 74 72 69 62 75 74 69 6f 6e 2e 0a 23   distribution..#
0280: 0a 23 20 54 48 49 53 20 53 4f 46 54 57 41 52 45  .# THIS SOFTWARE
0290: 20 49 53 20 50 52 4f 56 49 44 45 44 20 42 59 20   IS PROVIDED BY 
02a0: 54 48 45 20 43 4f 50 59 52 49 47 48 54 20 48 4f  THE COPYRIGHT HO
02b0: 4c 44 45 52 53 20 41 4e 44 20 43 4f 4e 54 52 49  LDERS AND CONTRI
02c0: 42 55 54 4f 52 53 20 22 41 53 20 0a 23 20 49 53  BUTORS "AS .# IS
02d0: 22 20 41 4e 44 20 41 4e 59 20 45 58 50 52 45 53  " AND ANY EXPRES
02e0: 53 20 4f 52 20 49 4d 50 4c 49 45 44 20 57 41 52  S OR IMPLIED WAR
02f0: 52 41 4e 54 49 45 53 2c 20 49 4e 43 4c 55 44 49  RANTIES, INCLUDI
0300: 4e 47 2c 20 42 55 54 20 4e 4f 54 20 4c 49 4d 49  NG, BUT NOT LIMI
0310: 54 45 44 20 0a 23 20 54 4f 2c 20 54 48 45 20 49  TED .# TO, THE I
0320: 4d 50 4c 49 45 44 20 57 41 52 52 41 4e 54 49 45  MPLIED WARRANTIE
0330: 53 20 4f 46 20 4d 45 52 43 48 41 4e 54 41 42 49  S OF MERCHANTABI
0340: 4c 49 54 59 20 41 4e 44 20 46 49 54 4e 45 53 53  LITY AND FITNESS
0350: 20 46 4f 52 20 41 20 0a 23 20 50 41 52 54 49 43   FOR A .# PARTIC
0360: 55 4c 41 52 20 50 55 52 50 4f 53 45 20 41 52 45  ULAR PURPOSE ARE
0370: 20 44 49 53 43 4c 41 49 4d 45 44 2e 20 49 4e 20   DISCLAIMED. IN 
0380: 4e 4f 20 45 56 45 4e 54 20 53 48 41 4c 4c 20 54  NO EVENT SHALL T
0390: 48 45 20 43 4f 50 59 52 49 47 48 54 20 0a 23 20  HE COPYRIGHT .# 
03a0: 48 4f 4c 44 45 52 20 4f 52 20 43 4f 4e 54 52 49  HOLDER OR CONTRI
03b0: 42 55 54 4f 52 53 20 42 45 20 4c 49 41 42 4c 45  BUTORS BE LIABLE
03c0: 20 46 4f 52 20 41 4e 59 20 44 49 52 45 43 54 2c   FOR ANY DIRECT,
03d0: 20 49 4e 44 49 52 45 43 54 2c 20 49 4e 43 49 44   INDIRECT, INCID
03e0: 45 4e 54 41 4c 2c 20 0a 23 20 53 50 45 43 49 41  ENTAL, .# SPECIA
03f0: 4c 2c 20 45 58 45 4d 50 4c 41 52 59 2c 20 4f 52  L, EXEMPLARY, OR
0400: 20 43 4f 4e 53 45 51 55 45 4e 54 49 41 4c 20 44   CONSEQUENTIAL D
0410: 41 4d 41 47 45 53 20 28 49 4e 43 4c 55 44 49 4e  AMAGES (INCLUDIN
0420: 47 2c 20 42 55 54 20 4e 4f 54 20 4c 49 4d 49 54  G, BUT NOT LIMIT
0430: 45 44 20 0a 23 20 54 4f 2c 20 50 52 4f 43 55 52  ED .# TO, PROCUR
0440: 45 4d 45 4e 54 20 4f 46 20 53 55 42 53 54 49 54  EMENT OF SUBSTIT
0450: 55 54 45 20 47 4f 4f 44 53 20 4f 52 20 53 45 52  UTE GOODS OR SER
0460: 56 49 43 45 53 3b 20 4c 4f 53 53 20 4f 46 20 55  VICES; LOSS OF U
0470: 53 45 2c 20 44 41 54 41 2c 20 4f 52 20 0a 23 20  SE, DATA, OR .# 
0480: 50 52 4f 46 49 54 53 3b 20 4f 52 20 42 55 53 49  PROFITS; OR BUSI
0490: 4e 45 53 53 20 49 4e 54 45 52 52 55 50 54 49 4f  NESS INTERRUPTIO
04a0: 4e 29 20 48 4f 57 45 56 45 52 20 43 41 55 53 45  N) HOWEVER CAUSE
04b0: 44 20 41 4e 44 20 4f 4e 20 41 4e 59 20 54 48 45  D AND ON ANY THE
04c0: 4f 52 59 20 4f 46 20 0a 23 20 4c 49 41 42 49 4c  ORY OF .# LIABIL
04d0: 49 54 59 2c 20 57 48 45 54 48 45 52 20 49 4e 20  ITY, WHETHER IN 
04e0: 43 4f 4e 54 52 41 43 54 2c 20 53 54 52 49 43 54  CONTRACT, STRICT
04f0: 20 4c 49 41 42 49 4c 49 54 59 2c 20 4f 52 20 54   LIABILITY, OR T
0500: 4f 52 54 20 28 49 4e 43 4c 55 44 49 4e 47 20 0a  ORT (INCLUDING .
0510: 23 20 4e 45 47 4c 49 47 45 4e 43 45 20 4f 52 20  # NEGLIGENCE OR 
0520: 4f 54 48 45 52 57 49 53 45 29 20 41 52 49 53 49  OTHERWISE) ARISI
0530: 4e 47 20 49 4e 20 41 4e 59 20 57 41 59 20 4f 55  NG IN ANY WAY OU
0540: 54 20 4f 46 20 54 48 45 20 55 53 45 20 4f 46 20  T OF THE USE OF 
0550: 54 48 49 53 20 0a 23 20 53 4f 46 54 57 41 52 45  THIS .# SOFTWARE
0560: 2c 20 45 56 45 4e 20 49 46 20 41 44 56 49 53 45  , EVEN IF ADVISE
0570: 44 20 4f 46 20 54 48 45 20 50 4f 53 53 49 42 49  D OF THE POSSIBI
0580: 4c 49 54 59 20 4f 46 20 53 55 43 48 20 44 41 4d  LITY OF SUCH DAM
0590: 41 47 45 2e 0a 0a 73 65 74 20 70 61 73 73 77 6f  AGE...set passwo
05a0: 72 64 46 69 6c 65 20 5b 6c 69 6e 64 65 78 20 24  rdFile [lindex $
05b0: 61 72 67 76 20 30 5d 0a 73 65 74 20 61 63 74 69  argv 0].set acti
05c0: 6f 6e 20 5b 6c 69 6e 64 65 78 20 24 61 72 67 76  on [lindex $argv
05d0: 20 31 5d 0a 0a 73 65 74 20 76 61 6c 69 64 43 6f   1]..set validCo
05e0: 6d 6d 61 6e 64 73 20 5b 6c 69 73 74 20 22 6c 69  mmands [list "li
05f0: 73 74 4c 6f 63 61 6c 4b 65 79 73 22 20 22 6c 69  stLocalKeys" "li
0600: 73 74 50 61 73 73 77 6f 72 64 73 22 20 22 6c 69  stPasswords" "li
0610: 73 74 41 76 61 69 6c 61 62 6c 65 50 61 73 73 77  stAvailablePassw
0620: 6f 72 64 73 22 20 22 6c 69 73 74 55 73 65 72 73  ords" "listUsers
0630: 22 20 22 61 64 64 55 73 65 72 22 20 22 61 64 64  " "addUser" "add
0640: 50 61 73 73 77 6f 72 64 22 20 22 61 75 74 68 6f  Password" "autho
0650: 72 69 7a 65 55 73 65 72 22 20 22 61 75 74 68 6f  rizeUser" "autho
0660: 72 69 7a 65 55 73 65 72 73 22 20 22 64 65 61 75  rizeUsers" "deau
0670: 74 68 6f 72 69 7a 65 55 73 65 72 22 20 22 64 65  thorizeUser" "de
0680: 61 75 74 68 6f 72 69 7a 65 55 73 65 72 73 22 20  authorizeUsers" 
0690: 22 67 65 74 50 61 73 73 77 6f 72 64 22 20 22 75  "getPassword" "u
06a0: 70 64 61 74 65 50 61 73 73 77 6f 72 64 22 20 22  pdatePassword" "
06b0: 64 65 6c 65 74 65 50 61 73 73 77 6f 72 64 22 20  deletePassword" 
06c0: 22 68 65 6c 70 22 20 22 77 68 6f 61 6d 69 22 5d  "help" "whoami"]
06d0: 0a 0a 70 72 6f 63 20 5f 61 72 67 44 65 73 63 72  ..proc _argDescr
06e0: 69 70 74 69 6f 6e 20 7b 63 6f 6d 6d 61 6e 64 20  iption {command 
06f0: 61 72 67 4e 61 6d 65 7d 20 7b 0a 09 73 77 69 74  argName} {..swit
0700: 63 68 20 2d 2d 20 24 61 72 67 4e 61 6d 65 20 7b  ch -- $argName {
0710: 0a 09 09 22 70 61 73 73 77 6f 72 64 4e 61 6d 65  ..."passwordName
0720: 22 20 7b 0a 09 09 09 72 65 74 75 72 6e 20 22 24  " {....return "$
0730: 61 72 67 4e 61 6d 65 20 2d 20 4e 61 6d 65 20 6f  argName - Name o
0740: 66 20 74 68 65 20 70 61 73 73 77 6f 72 64 20 65  f the password e
0750: 6e 74 72 79 22 0a 09 09 7d 0a 09 09 22 6b 65 79  ntry"...}..."key
0760: 22 20 7b 0a 09 09 09 72 65 74 75 72 6e 20 22 24  " {....return "$
0770: 61 72 67 4e 61 6d 65 20 2d 20 50 75 62 6c 69 63  argName - Public
0780: 20 6b 65 79 20 6f 66 20 74 68 65 20 75 73 65 72   key of the user
0790: 22 0a 09 09 7d 0a 09 09 22 70 61 73 73 77 6f 72  "...}..."passwor
07a0: 64 22 20 7b 0a 09 09 09 72 65 74 75 72 6e 20 22  d" {....return "
07b0: 24 61 72 67 4e 61 6d 65 20 2d 20 41 20 70 6c 61  $argName - A pla
07c0: 69 6e 2d 74 65 78 74 20 70 61 73 73 77 6f 72 64  in-text password
07d0: 22 0a 09 09 7d 0a 09 09 22 75 73 65 72 4e 61 6d  "...}..."userNam
07e0: 65 22 20 7b 0a 09 09 09 72 65 74 75 72 6e 20 22  e" {....return "
07f0: 24 61 72 67 4e 61 6d 65 20 2d 20 41 20 75 73 65  $argName - A use
0800: 72 20 6e 61 6d 65 22 0a 09 09 7d 0a 09 09 22 61  r name"...}..."a
0810: 63 74 69 6f 6e 22 20 7b 0a 09 09 09 72 65 74 75  ction" {....retu
0820: 72 6e 20 22 24 61 72 67 4e 61 6d 65 20 2d 20 41  rn "$argName - A
0830: 6e 20 61 63 74 69 6f 6e 20 6e 61 6d 65 20 66 6f  n action name fo
0840: 72 20 68 65 6c 70 20 77 69 74 68 22 0a 09 09 7d  r help with"...}
0850: 0a 09 09 22 61 72 67 73 22 20 7b 0a 09 09 09 72  ..."args" {....r
0860: 65 74 75 72 6e 20 22 75 73 65 72 4c 69 73 74 20  eturn "userList 
0870: 2d 20 41 20 6c 69 73 74 20 6f 66 20 75 73 65 72  - A list of user
0880: 6e 61 6d 65 73 22 0a 09 09 7d 0a 09 7d 0a 0a 09  names"...}..}...
0890: 72 65 74 75 72 6e 20 22 3c 55 4e 4b 4e 4f 57 4e  return "<UNKNOWN
08a0: 3e 22 0a 7d 0a 0a 70 72 6f 63 20 5f 70 72 69 6e  >".}..proc _prin
08b0: 74 48 65 6c 70 20 7b 63 68 61 6e 6e 65 6c 20 63  tHelp {channel c
08c0: 6f 6d 6d 61 6e 64 7d 20 7b 0a 09 69 66 20 7b 24  ommand} {..if {$
08d0: 63 6f 6d 6d 61 6e 64 20 3d 3d 20 22 22 7d 20 7b  command == ""} {
08e0: 0a 09 09 70 75 74 73 20 24 63 68 61 6e 6e 65 6c  ...puts $channel
08f0: 20 22 55 73 61 67 65 3a 20 68 75 6e 74 65 72 32   "Usage: hunter2
0900: 20 3c 70 61 73 73 77 6f 72 64 46 69 6c 65 3e 20   <passwordFile> 
0910: 3c 61 63 74 69 6f 6e 3e 20 5c 5b 3c 61 63 74 69  <action> \[<acti
0920: 6f 6e 41 72 67 73 2e 2e 2e 3e 5c 5d 22 0a 09 09  onArgs...>\]"...
0930: 70 75 74 73 20 24 63 68 61 6e 6e 65 6c 20 22 22  puts $channel ""
0940: 0a 09 09 70 75 74 73 20 24 63 68 61 6e 6e 65 6c  ...puts $channel
0950: 20 22 41 63 74 69 6f 6e 73 3a 22 0a 09 09 70 75   "Actions:"...pu
0960: 74 73 20 24 63 68 61 6e 6e 65 6c 20 22 20 20 20  ts $channel "   
0970: 20 5b 6a 6f 69 6e 20 24 3a 3a 76 61 6c 69 64 43   [join $::validC
0980: 6f 6d 6d 61 6e 64 73 20 7b 2c 20 7d 5d 22 0a 09  ommands {, }]"..
0990: 09 70 75 74 73 20 24 63 68 61 6e 6e 65 6c 20 22  .puts $channel "
09a0: 22 0a 09 09 70 75 74 73 20 24 63 68 61 6e 6e 65  "...puts $channe
09b0: 6c 20 22 20 20 20 20 68 75 6e 74 65 72 32 20 3c  l "    hunter2 <
09c0: 66 69 6c 65 3e 20 68 65 6c 70 20 3c 61 63 74 69  file> help <acti
09d0: 6f 6e 3e 20 20 20 20 66 6f 72 20 68 65 6c 70 20  on>    for help 
09e0: 77 69 74 68 20 61 6e 20 61 63 74 69 6f 6e 22 0a  with an action".
09f0: 09 7d 20 65 6c 73 65 20 7b 0a 09 09 73 65 74 20  .} else {...set 
0a00: 61 72 67 73 20 5b 69 6e 66 6f 20 61 72 67 73 20  args [info args 
0a10: 24 63 6f 6d 6d 61 6e 64 5d 0a 09 09 73 65 74 20  $command]...set 
0a20: 70 72 69 6e 74 41 72 67 73 20 5b 6c 69 73 74 5d  printArgs [list]
0a30: 0a 09 09 66 6f 72 65 61 63 68 20 61 72 67 20 24  ...foreach arg $
0a40: 61 72 67 73 20 7b 0a 09 09 09 69 66 20 7b 24 61  args {....if {$a
0a50: 72 67 20 3d 3d 20 22 61 72 67 73 22 7d 20 7b 0a  rg == "args"} {.
0a60: 09 09 09 09 73 65 74 20 61 72 67 20 22 75 73 65  ....set arg "use
0a70: 72 4c 69 73 74 22 0a 09 09 09 7d 0a 09 09 09 6c  rList"....}....l
0a80: 61 70 70 65 6e 64 20 70 72 69 6e 74 41 72 67 73  append printArgs
0a90: 20 22 3c 24 61 72 67 3e 22 0a 09 09 7d 0a 0a 09   "<$arg>"...}...
0aa0: 09 70 75 74 73 20 24 63 68 61 6e 6e 65 6c 20 22  .puts $channel "
0ab0: 55 73 61 67 65 3a 20 68 75 6e 74 65 72 32 20 3c  Usage: hunter2 <
0ac0: 70 61 73 73 77 6f 72 64 46 69 6c 65 3e 20 24 63  passwordFile> $c
0ad0: 6f 6d 6d 61 6e 64 20 5b 6a 6f 69 6e 20 24 70 72  ommand [join $pr
0ae0: 69 6e 74 41 72 67 73 5d 22 0a 0a 09 09 69 66 20  intArgs]"....if 
0af0: 7b 5b 6c 6c 65 6e 67 74 68 20 24 61 72 67 73 5d  {[llength $args]
0b00: 20 3e 20 30 7d 20 7b 0a 09 09 09 70 75 74 73 20   > 0} {....puts 
0b10: 24 63 68 61 6e 6e 65 6c 20 22 22 0a 09 09 09 70  $channel ""....p
0b20: 75 74 73 20 24 63 68 61 6e 6e 65 6c 20 22 41 72  uts $channel "Ar
0b30: 67 75 6d 65 6e 74 73 3a 22 0a 09 09 09 66 6f 72  guments:"....for
0b40: 65 61 63 68 20 61 72 67 20 24 61 72 67 73 20 7b  each arg $args {
0b50: 0a 09 09 09 09 70 75 74 73 20 24 63 68 61 6e 6e  .....puts $chann
0b60: 65 6c 20 22 20 20 20 20 5b 5f 61 72 67 44 65 73  el "    [_argDes
0b70: 63 72 69 70 74 69 6f 6e 20 24 63 6f 6d 6d 61 6e  cription $comman
0b80: 64 20 24 61 72 67 5d 22 0a 09 09 09 7d 0a 09 09  d $arg]"....}...
0b90: 7d 0a 09 7d 0a 7d 0a 0a 69 66 20 7b 5b 6c 6c 65  }..}.}..if {[lle
0ba0: 6e 67 74 68 20 24 61 72 67 76 5d 20 3c 20 32 7d  ngth $argv] < 2}
0bb0: 20 7b 0a 09 5f 70 72 69 6e 74 48 65 6c 70 20 73   {.._printHelp s
0bc0: 74 64 65 72 72 20 22 22 0a 0a 09 65 78 69 74 20  tderr ""...exit 
0bd0: 31 0a 7d 0a 0a 73 65 74 20 61 72 67 76 20 5b 6c  1.}..set argv [l
0be0: 72 61 6e 67 65 20 24 61 72 67 76 20 32 20 65 6e  range $argv 2 en
0bf0: 64 5d 0a 0a 70 61 63 6b 61 67 65 20 72 65 71 75  d]..package requ
0c00: 69 72 65 20 73 71 6c 69 74 65 33 0a 70 61 63 6b  ire sqlite3.pack
0c10: 61 67 65 20 72 65 71 75 69 72 65 20 70 6c 61 74  age require plat
0c20: 66 6f 72 6d 0a 0a 6c 61 70 70 65 6e 64 20 3a 3a  form..lappend ::
0c30: 61 75 74 6f 5f 70 61 74 68 20 5b 66 69 6c 65 20  auto_path [file 
0c40: 6a 6f 69 6e 20 5b 66 69 6c 65 20 64 69 72 6e 61  join [file dirna
0c50: 6d 65 20 5b 69 6e 66 6f 20 73 63 72 69 70 74 5d  me [info script]
0c60: 5d 20 6c 69 62 20 5b 70 6c 61 74 66 6f 72 6d 3a  ] lib [platform:
0c70: 3a 69 64 65 6e 74 69 66 79 5d 5d 0a 6c 61 70 70  :identify]].lapp
0c80: 65 6e 64 20 3a 3a 61 75 74 6f 5f 70 61 74 68 20  end ::auto_path 
0c90: 5b 66 69 6c 65 20 6a 6f 69 6e 20 5b 66 69 6c 65  [file join [file
0ca0: 20 64 69 72 6e 61 6d 65 20 5b 69 6e 66 6f 20 73   dirname [info s
0cb0: 63 72 69 70 74 5d 5d 20 6c 69 62 20 5b 70 6c 61  cript]] lib [pla
0cc0: 74 66 6f 72 6d 3a 3a 67 65 6e 65 72 69 63 5d 5d  tform::generic]]
0cd0: 0a 6c 61 70 70 65 6e 64 20 3a 3a 61 75 74 6f 5f  .lappend ::auto_
0ce0: 70 61 74 68 20 5b 66 69 6c 65 20 6a 6f 69 6e 20  path [file join 
0cf0: 5b 66 69 6c 65 20 64 69 72 6e 61 6d 65 20 5b 69  [file dirname [i
0d00: 6e 66 6f 20 73 63 72 69 70 74 5d 5d 20 6c 69 62  nfo script]] lib
0d10: 5d 0a 0a 70 61 63 6b 61 67 65 20 72 65 71 75 69  ]..package requi
0d20: 72 65 20 70 6b 69 0a 70 61 63 6b 61 67 65 20 72  re pki.package r
0d30: 65 71 75 69 72 65 20 70 6b 69 3a 3a 70 6b 63 73  equire pki::pkcs
0d40: 31 31 0a 70 61 63 6b 61 67 65 20 72 65 71 75 69  11.package requi
0d50: 72 65 20 61 65 73 0a 70 61 63 6b 61 67 65 20 72  re aes.package r
0d60: 65 71 75 69 72 65 20 73 68 61 32 35 36 0a 0a 23  equire sha256..#
0d70: 20 42 61 63 6b 70 6f 72 74 73 20 66 6f 72 20 6f   Backports for o
0d80: 6c 64 65 72 20 76 65 72 73 69 6f 6e 73 20 6f 66  lder versions of
0d90: 20 22 70 6b 69 22 0a 70 72 6f 63 20 3a 3a 70 6b   "pki".proc ::pk
0da0: 69 3a 3a 70 6b 63 73 3a 3a 70 61 72 73 65 5f 70  i::pkcs::parse_p
0db0: 75 62 6c 69 63 5f 6b 65 79 20 7b 6b 65 79 20 7b  ublic_key {key {
0dc0: 70 61 73 73 77 6f 72 64 20 22 22 7d 7d 20 7b 0a  password ""}} {.
0dd0: 20 20 20 20 20 20 20 20 61 72 72 61 79 20 73 65          array se
0de0: 74 20 70 61 72 73 65 64 5f 6b 65 79 20 5b 3a 3a  t parsed_key [::
0df0: 70 6b 69 3a 3a 5f 70 61 72 73 65 5f 70 65 6d 20  pki::_parse_pem 
0e00: 24 6b 65 79 20 22 2d 2d 2d 2d 2d 42 45 47 49 4e  $key "-----BEGIN
0e10: 20 50 55 42 4c 49 43 20 4b 45 59 2d 2d 2d 2d 2d   PUBLIC KEY-----
0e20: 22 20 22 2d 2d 2d 2d 2d 45 4e 44 20 50 55 42 4c  " "-----END PUBL
0e30: 49 43 20 4b 45 59 2d 2d 2d 2d 2d 22 20 24 70 61  IC KEY-----" $pa
0e40: 73 73 77 6f 72 64 5d 0a 0a 20 20 20 20 20 20 20  ssword]..       
0e50: 20 73 65 74 20 6b 65 79 5f 73 65 71 20 24 70 61   set key_seq $pa
0e60: 72 73 65 64 5f 6b 65 79 28 64 61 74 61 29 0a 0a  rsed_key(data)..
0e70: 20 20 20 20 20 20 20 20 3a 3a 61 73 6e 3a 3a 61          ::asn::a
0e80: 73 6e 47 65 74 53 65 71 75 65 6e 63 65 20 6b 65  snGetSequence ke
0e90: 79 5f 73 65 71 20 70 75 62 6b 65 79 69 6e 66 6f  y_seq pubkeyinfo
0ea0: 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20  .               
0eb0: 20 3a 3a 61 73 6e 3a 3a 61 73 6e 47 65 74 53 65   ::asn::asnGetSe
0ec0: 71 75 65 6e 63 65 20 70 75 62 6b 65 79 69 6e 66  quence pubkeyinf
0ed0: 6f 20 70 75 62 6b 65 79 5f 61 6c 67 6f 69 64 0a  o pubkey_algoid.
0ee0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
0ef0: 20 20 20 20 20 20 20 20 3a 3a 61 73 6e 3a 3a 61          ::asn::a
0f00: 73 6e 47 65 74 4f 62 6a 65 63 74 49 64 65 6e 74  snGetObjectIdent
0f10: 69 66 69 65 72 20 70 75 62 6b 65 79 5f 61 6c 67  ifier pubkey_alg
0f20: 6f 69 64 20 6f 69 64 0a 20 20 20 20 20 20 20 20  oid oid.        
0f30: 20 20 20 20 20 20 20 20 3a 3a 61 73 6e 3a 3a 61          ::asn::a
0f40: 73 6e 47 65 74 42 69 74 53 74 72 69 6e 67 20 70  snGetBitString p
0f50: 75 62 6b 65 79 69 6e 66 6f 20 70 75 62 6b 65 79  ubkeyinfo pubkey
0f60: 0a 20 20 20 20 20 20 20 20 73 65 74 20 72 65 74  .        set ret
0f70: 28 70 75 62 6b 65 79 5f 61 6c 67 6f 29 20 5b 3a  (pubkey_algo) [:
0f80: 3a 70 6b 69 3a 3a 5f 6f 69 64 5f 6e 75 6d 62 65  :pki::_oid_numbe
0f90: 72 5f 74 6f 5f 6e 61 6d 65 20 24 6f 69 64 5d 0a  r_to_name $oid].
0fa0: 0a 20 20 20 20 20 20 20 20 73 77 69 74 63 68 20  .        switch 
0fb0: 2d 2d 20 24 72 65 74 28 70 75 62 6b 65 79 5f 61  -- $ret(pubkey_a
0fc0: 6c 67 6f 29 20 7b 0a 20 20 20 20 20 20 20 20 20  lgo) {.         
0fd0: 20 20 20 20 20 20 20 22 72 73 61 45 6e 63 72 79         "rsaEncry
0fe0: 70 74 69 6f 6e 22 20 7b 0a 20 20 20 20 20 20 20  ption" {.       
0ff0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
1000: 20 73 65 74 20 70 75 62 6b 65 79 20 5b 62 69 6e   set pubkey [bin
1010: 61 72 79 20 66 6f 72 6d 61 74 20 42 2a 20 24 70  ary format B* $p
1020: 75 62 6b 65 79 5d 0a 0a 20 20 20 20 20 20 20 20  ubkey]..        
1030: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
1040: 3a 3a 61 73 6e 3a 3a 61 73 6e 47 65 74 53 65 71  ::asn::asnGetSeq
1050: 75 65 6e 63 65 20 70 75 62 6b 65 79 20 70 75 62  uence pubkey pub
1060: 6b 65 79 5f 70 61 72 74 73 0a 20 20 20 20 20 20  key_parts.      
1070: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
1080: 20 20 20 20 20 20 20 20 20 20 3a 3a 61 73 6e 3a            ::asn:
1090: 3a 61 73 6e 47 65 74 42 69 67 49 6e 74 65 67 65  :asnGetBigIntege
10a0: 72 20 70 75 62 6b 65 79 5f 70 61 72 74 73 20 72  r pubkey_parts r
10b0: 65 74 28 6e 29 0a 20 20 20 20 20 20 20 20 20 20  et(n).          
10c0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
10d0: 20 20 20 20 20 20 3a 3a 61 73 6e 3a 3a 61 73 6e        ::asn::asn
10e0: 47 65 74 42 69 67 49 6e 74 65 67 65 72 20 70 75  GetBigInteger pu
10f0: 62 6b 65 79 5f 70 61 72 74 73 20 72 65 74 28 65  bkey_parts ret(e
1100: 29 0a 0a 20 20 20 20 20 20 20 20 20 20 20 20 20  )..             
1110: 20 20 20 20 20 20 20 20 20 20 20 73 65 74 20 72             set r
1120: 65 74 28 6e 29 20 5b 3a 3a 6d 61 74 68 3a 3a 62  et(n) [::math::b
1130: 69 67 6e 75 6d 3a 3a 74 6f 73 74 72 20 24 72 65  ignum::tostr $re
1140: 74 28 6e 29 5d 0a 20 20 20 20 20 20 20 20 20 20  t(n)].          
1150: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 73 65                se
1160: 74 20 72 65 74 28 65 29 20 5b 3a 3a 6d 61 74 68  t ret(e) [::math
1170: 3a 3a 62 69 67 6e 75 6d 3a 3a 74 6f 73 74 72 20  ::bignum::tostr 
1180: 24 72 65 74 28 65 29 5d 0a 20 20 20 20 20 20 20  $ret(e)].       
1190: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
11a0: 20 73 65 74 20 72 65 74 28 6c 29 20 5b 65 78 70   set ret(l) [exp
11b0: 72 20 7b 69 6e 74 28 5b 3a 3a 70 6b 69 3a 3a 5f  r {int([::pki::_
11c0: 62 69 74 73 20 24 72 65 74 28 6e 29 5d 20 2f 20  bits $ret(n)] / 
11d0: 38 2e 30 30 30 30 20 2b 20 30 2e 35 29 20 2a 20  8.0000 + 0.5) * 
11e0: 38 7d 5d 0a 20 20 20 20 20 20 20 20 20 20 20 20  8}].            
11f0: 20 20 20 20 20 20 20 20 20 20 20 20 73 65 74 20              set 
1200: 72 65 74 28 74 79 70 65 29 20 72 73 61 0a 20 20  ret(type) rsa.  
1210: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 7d 0a                }.
1220: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
1230: 64 65 66 61 75 6c 74 20 7b 0a 20 20 20 20 20 20  default {.      
1240: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
1250: 20 20 65 72 72 6f 72 20 22 55 6e 6b 6e 6f 77 6e    error "Unknown
1260: 20 61 6c 67 6f 72 69 74 68 6d 22 0a 20 20 20 20   algorithm".    
1270: 20 20 20 20 20 20 20 20 20 20 20 20 7d 0a 20 20              }.  
1280: 20 20 20 20 20 20 7d 0a 0a 20 20 20 20 20 20 20        }..       
1290: 20 72 65 74 75 72 6e 20 5b 61 72 72 61 79 20 67   return [array g
12a0: 65 74 20 72 65 74 5d 0a 7d 0a 0a 70 72 6f 63 20  et ret].}..proc 
12b0: 3a 3a 70 6b 69 3a 3a 72 73 61 3a 3a 73 65 72 69  ::pki::rsa::seri
12c0: 61 6c 69 7a 65 5f 70 75 62 6c 69 63 5f 6b 65 79  alize_public_key
12d0: 20 7b 6b 65 79 6c 69 73 74 7d 20 7b 0a 20 20 20   {keylist} {.   
12e0: 20 20 20 20 20 61 72 72 61 79 20 73 65 74 20 6b       array set k
12f0: 65 79 20 24 6b 65 79 6c 69 73 74 0a 0a 20 20 20  ey $keylist..   
1300: 20 20 20 20 20 66 6f 72 65 61 63 68 20 65 6e 74       foreach ent
1310: 72 79 20 5b 6c 69 73 74 20 6e 20 65 5d 20 7b 0a  ry [list n e] {.
1320: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
1330: 69 66 20 7b 21 5b 69 6e 66 6f 20 65 78 69 73 74  if {![info exist
1340: 73 20 6b 65 79 28 24 65 6e 74 72 79 29 5d 7d 20  s key($entry)]} 
1350: 7b 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 20  {.              
1360: 20 20 20 20 20 20 20 20 20 20 72 65 74 75 72 6e            return
1370: 20 2d 63 6f 64 65 20 65 72 72 6f 72 20 22 4b 65   -code error "Ke
1380: 79 20 64 6f 65 73 20 6e 6f 74 20 63 6f 6e 74 61  y does not conta
1390: 69 6e 20 61 6e 20 65 6c 65 6d 65 6e 74 20 24 65  in an element $e
13a0: 6e 74 72 79 22 0a 20 20 20 20 20 20 20 20 20 20  ntry".          
13b0: 20 20 20 20 20 20 7d 0a 20 20 20 20 20 20 20 20        }.        
13c0: 7d 0a 0a 20 20 20 20 20 20 20 20 73 65 74 20 70  }..        set p
13d0: 75 62 6b 65 79 20 5b 3a 3a 61 73 6e 3a 3a 61 73  ubkey [::asn::as
13e0: 6e 53 65 71 75 65 6e 63 65 20 5c 0a 20 20 20 20  nSequence \.    
13f0: 20 20 20 20 20 20 20 20 20 20 20 20 5b 3a 3a 61              [::a
1400: 73 6e 3a 3a 61 73 6e 42 69 67 49 6e 74 65 67 65  sn::asnBigIntege
1410: 72 20 5b 3a 3a 6d 61 74 68 3a 3a 62 69 67 6e 75  r [::math::bignu
1420: 6d 3a 3a 66 72 6f 6d 73 74 72 20 24 6b 65 79 28  m::fromstr $key(
1430: 6e 29 5d 5d 20 5c 0a 20 20 20 20 20 20 20 20 20  n)]] \.         
1440: 20 20 20 20 20 20 20 5b 3a 3a 61 73 6e 3a 3a 61         [::asn::a
1450: 73 6e 42 69 67 49 6e 74 65 67 65 72 20 5b 3a 3a  snBigInteger [::
1460: 6d 61 74 68 3a 3a 62 69 67 6e 75 6d 3a 3a 66 72  math::bignum::fr
1470: 6f 6d 73 74 72 20 24 6b 65 79 28 65 29 5d 5d 20  omstr $key(e)]] 
1480: 5c 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 20  \.              
1490: 20 20 5d 20 20 0a 20 20 20 20 20 20 20 20 73 65    ]  .        se
14a0: 74 20 70 75 62 6b 65 79 5f 61 6c 67 6f 5f 70 61  t pubkey_algo_pa
14b0: 72 61 6d 73 20 5b 3a 3a 61 73 6e 3a 3a 61 73 6e  rams [::asn::asn
14c0: 4e 75 6c 6c 5d 0a 0a 20 20 20 20 20 20 20 20 62  Null]..        b
14d0: 69 6e 61 72 79 20 73 63 61 6e 20 24 70 75 62 6b  inary scan $pubk
14e0: 65 79 20 42 2a 20 70 75 62 6b 65 79 5f 62 69 74  ey B* pubkey_bit
14f0: 73 74 72 69 6e 67 0a 0a 20 20 20 20 20 20 20 20  string..        
1500: 73 65 74 20 72 65 74 20 5b 3a 3a 61 73 6e 3a 3a  set ret [::asn::
1510: 61 73 6e 53 65 71 75 65 6e 63 65 20 5c 0a 20 20  asnSequence \.  
1520: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 5b 3a                [:
1530: 3a 61 73 6e 3a 3a 61 73 6e 53 65 71 75 65 6e 63  :asn::asnSequenc
1540: 65 20 5c 0a 20 20 20 20 20 20 20 20 20 20 20 20  e \.            
1550: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
1560: 20 20 20 20 5b 3a 3a 61 73 6e 3a 3a 61 73 6e 4f      [::asn::asnO
1570: 62 6a 65 63 74 49 64 65 6e 74 69 66 69 65 72 20  bjectIdentifier 
1580: 5b 3a 3a 70 6b 69 3a 3a 5f 6f 69 64 5f 6e 61 6d  [::pki::_oid_nam
1590: 65 5f 74 6f 5f 6e 75 6d 62 65 72 20 72 73 61 45  e_to_number rsaE
15a0: 6e 63 72 79 70 74 69 6f 6e 5d 5d 20 5c 0a 20 20  ncryption]] \.  
15b0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
15c0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 24 70                $p
15d0: 75 62 6b 65 79 5f 61 6c 67 6f 5f 70 61 72 61 6d  ubkey_algo_param
15e0: 73 20 5c 0a 20 20 20 20 20 20 20 20 20 20 20 20  s \.            
15f0: 20 20 20 20 20 20 20 20 20 20 20 20 5d 20 5c 0a              ] \.
1600: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
1610: 20 20 20 20 20 20 20 20 5b 3a 3a 61 73 6e 3a 3a          [::asn::
1620: 61 73 6e 42 69 74 53 74 72 69 6e 67 20 24 70 75  asnBitString $pu
1630: 62 6b 65 79 5f 62 69 74 73 74 72 69 6e 67 5d 20  bkey_bitstring] 
1640: 5c 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 20  \.              
1650: 20 20 20 20 20 20 20 20 20 20 5d 0a 0a 20 20 20            ]..   
1660: 20 20 20 20 20 72 65 74 75 72 6e 20 5b 6c 69 73       return [lis
1670: 74 20 64 61 74 61 20 24 72 65 74 20 62 65 67 69  t data $ret begi
1680: 6e 20 22 2d 2d 2d 2d 2d 42 45 47 49 4e 20 50 55  n "-----BEGIN PU
1690: 42 4c 49 43 20 4b 45 59 2d 2d 2d 2d 2d 22 20 65  BLIC KEY-----" e
16a0: 6e 64 20 22 2d 2d 2d 2d 2d 45 4e 44 20 50 55 42  nd "-----END PUB
16b0: 4c 49 43 20 4b 45 59 2d 2d 2d 2d 2d 22 5d 0a 7d  LIC KEY-----"].}
16c0: 0a 23 20 45 6e 64 20 62 61 63 6b 70 6f 72 74 73  .# End backports
16d0: 0a 0a 23 20 53 74 61 72 74 20 69 6e 74 65 72 6e  ..# Start intern
16e0: 61 6c 20 66 75 6e 63 74 69 6f 6e 73 0a 70 72 6f  al functions.pro
16f0: 63 20 5f 6c 69 73 74 43 65 72 74 69 66 69 63 61  c _listCertifica
1700: 74 65 73 20 7b 7d 20 7b 0a 09 69 66 20 7b 21 5b  tes {} {..if {![
1710: 69 6e 66 6f 20 65 78 69 73 74 73 20 3a 3a 65 6e  info exists ::en
1720: 76 28 50 4b 43 53 31 31 4d 4f 44 55 4c 45 29 5d  v(PKCS11MODULE)]
1730: 7d 20 7b 0a 09 09 72 65 74 75 72 6e 20 5b 6c 69  } {...return [li
1740: 73 74 5d 0a 09 7d 0a 0a 09 73 65 74 20 3a 3a 65  st]..}...set ::e
1750: 6e 76 28 43 41 43 4b 45 59 5f 4e 4f 5f 45 58 54  nv(CACKEY_NO_EXT
1760: 52 41 5f 43 45 52 54 53 29 20 31 0a 0a 09 73 65  RA_CERTS) 1...se
1770: 74 20 68 61 6e 64 6c 65 20 5b 3a 3a 70 6b 69 3a  t handle [::pki:
1780: 3a 70 6b 63 73 31 31 3a 3a 6c 6f 61 64 6d 6f 64  :pkcs11::loadmod
1790: 75 6c 65 20 24 3a 3a 65 6e 76 28 50 4b 43 53 31  ule $::env(PKCS1
17a0: 31 4d 4f 44 55 4c 45 29 5d 0a 0a 09 73 65 74 20  1MODULE)]...set 
17b0: 73 6c 6f 74 49 6e 66 6f 20 5b 6c 69 73 74 5d 0a  slotInfo [list].
17c0: 09 66 6f 72 65 61 63 68 20 73 6c 6f 74 20 5b 3a  .foreach slot [:
17d0: 3a 70 6b 69 3a 3a 70 6b 63 73 31 31 3a 3a 6c 69  :pki::pkcs11::li
17e0: 73 74 73 6c 6f 74 73 20 24 68 61 6e 64 6c 65 5d  stslots $handle]
17f0: 20 7b 0a 09 09 73 65 74 20 73 6c 6f 74 49 44 20   {...set slotID 
1800: 5b 6c 69 6e 64 65 78 20 24 73 6c 6f 74 20 30 5d  [lindex $slot 0]
1810: 0a 09 09 73 65 74 20 73 6c 6f 74 4c 61 62 65 6c  ...set slotLabel
1820: 20 5b 6c 69 6e 64 65 78 20 24 73 6c 6f 74 20 31   [lindex $slot 1
1830: 5d 0a 09 09 73 65 74 20 73 6c 6f 74 46 6c 61 67  ]...set slotFlag
1840: 73 20 5b 6c 69 6e 64 65 78 20 24 73 6c 6f 74 20  s [lindex $slot 
1850: 32 5d 0a 0a 09 09 69 66 20 7b 22 54 4f 4b 45 4e  2]....if {"TOKEN
1860: 5f 50 52 45 53 45 4e 54 22 20 6e 69 20 24 73 6c  _PRESENT" ni $sl
1870: 6f 74 46 6c 61 67 73 7d 20 7b 0a 09 09 09 63 6f  otFlags} {....co
1880: 6e 74 69 6e 75 65 0a 09 09 7d 0a 0a 09 09 69 66  ntinue...}....if
1890: 20 7b 22 54 4f 4b 45 4e 5f 49 4e 49 54 49 41 4c   {"TOKEN_INITIAL
18a0: 49 5a 45 44 22 20 6e 69 20 24 73 6c 6f 74 46 6c  IZED" ni $slotFl
18b0: 61 67 73 7d 20 7b 0a 09 09 09 63 6f 6e 74 69 6e  ags} {....contin
18c0: 75 65 0a 09 09 7d 0a 0a 09 09 73 65 74 20 73 6c  ue...}....set sl
18d0: 6f 74 50 72 6f 6d 70 74 46 6f 72 50 49 4e 20 66  otPromptForPIN f
18e0: 61 6c 73 65 0a 09 09 69 66 20 7b 22 50 52 4f 54  alse...if {"PROT
18f0: 45 43 54 45 44 5f 41 55 54 48 45 4e 54 49 43 41  ECTED_AUTHENTICA
1900: 54 49 4f 4e 5f 50 41 54 48 22 20 6e 69 20 24 73  TION_PATH" ni $s
1910: 6c 6f 74 46 6c 61 67 73 7d 20 7b 0a 09 09 09 69  lotFlags} {....i
1920: 66 20 7b 22 4c 4f 47 49 4e 5f 52 45 51 55 49 52  f {"LOGIN_REQUIR
1930: 45 44 22 20 69 6e 20 24 73 6c 6f 74 46 6c 61 67  ED" in $slotFlag
1940: 73 7d 20 7b 0a 09 09 09 09 73 65 74 20 73 6c 6f  s} {.....set slo
1950: 74 50 72 6f 6d 70 74 46 6f 72 50 49 4e 20 74 72  tPromptForPIN tr
1960: 75 65 0a 09 09 09 7d 0a 09 09 7d 0a 0a 09 09 66  ue....}...}....f
1970: 6f 72 65 61 63 68 20 63 65 72 74 20 5b 3a 3a 70  oreach cert [::p
1980: 6b 69 3a 3a 70 6b 63 73 31 31 3a 3a 6c 69 73 74  ki::pkcs11::list
1990: 63 65 72 74 73 20 24 68 61 6e 64 6c 65 20 24 73  certs $handle $s
19a0: 6c 6f 74 49 44 5d 20 7b 0a 09 09 09 73 65 74 20  lotID] {....set 
19b0: 70 75 62 6b 65 79 20 5b 62 69 6e 61 72 79 20 65  pubkey [binary e
19c0: 6e 63 6f 64 65 20 62 61 73 65 36 34 20 5b 64 69  ncode base64 [di
19d0: 63 74 20 67 65 74 20 5b 3a 3a 70 6b 69 3a 3a 72  ct get [::pki::r
19e0: 73 61 3a 3a 73 65 72 69 61 6c 69 7a 65 5f 70 75  sa::serialize_pu
19f0: 62 6c 69 63 5f 6b 65 79 20 24 63 65 72 74 5d 20  blic_key $cert] 
1a00: 64 61 74 61 5d 5d 0a 0a 09 09 09 6c 61 70 70 65  data]].....lappe
1a10: 6e 64 20 73 6c 6f 74 49 6e 66 6f 20 5b 6c 69 73  nd slotInfo [lis
1a20: 74 20 68 61 6e 64 6c 65 20 24 68 61 6e 64 6c 65  t handle $handle
1a30: 20 69 64 20 24 73 6c 6f 74 49 44 20 70 72 6f 6d   id $slotID prom
1a40: 70 74 20 24 73 6c 6f 74 50 72 6f 6d 70 74 46 6f  pt $slotPromptFo
1a50: 72 50 49 4e 20 63 65 72 74 20 24 63 65 72 74 20  rPIN cert $cert 
1a60: 70 75 62 6b 65 79 20 24 70 75 62 6b 65 79 5d 0a  pubkey $pubkey].
1a70: 09 09 7d 0a 09 7d 0a 0a 09 72 65 74 75 72 6e 20  ..}..}...return 
1a80: 24 73 6c 6f 74 49 6e 66 6f 0a 7d 0a 0a 70 72 6f  $slotInfo.}..pro
1a90: 63 20 5f 76 65 72 69 66 79 50 61 73 73 77 6f 72  c _verifyPasswor
1aa0: 64 20 7b 6e 61 6d 65 20 70 61 73 73 77 6f 72 64  d {name password
1ab0: 7d 20 7b 0a 09 73 65 74 20 70 75 62 6c 69 63 4b  } {..set publicK
1ac0: 65 79 73 20 5b 6c 69 73 74 5d 0a 0a 09 64 62 20  eys [list]...db 
1ad0: 65 76 61 6c 20 7b 53 45 4c 45 43 54 20 70 75 62  eval {SELECT pub
1ae0: 6c 69 63 4b 65 79 2c 20 76 65 72 69 66 69 63 61  licKey, verifica
1af0: 74 69 6f 6e 20 46 52 4f 4d 20 70 61 73 73 77 6f  tion FROM passwo
1b00: 72 64 73 20 57 48 45 52 45 20 6e 61 6d 65 20 3d  rds WHERE name =
1b10: 20 24 6e 61 6d 65 7d 20 72 6f 77 20 7b 0a 09 09   $name} row {...
1b20: 73 65 74 20 73 61 6c 74 20 5b 64 69 63 74 20 67  set salt [dict g
1b30: 65 74 20 24 72 6f 77 28 76 65 72 69 66 69 63 61  et $row(verifica
1b40: 74 69 6f 6e 29 20 73 61 6c 74 5d 0a 09 09 73 65  tion) salt]...se
1b50: 74 20 68 61 73 68 41 6c 67 6f 72 69 74 68 6d 20  t hashAlgorithm 
1b60: 5b 64 69 63 74 20 67 65 74 20 24 72 6f 77 28 76  [dict get $row(v
1b70: 65 72 69 66 69 63 61 74 69 6f 6e 29 20 68 61 73  erification) has
1b80: 68 41 6c 67 6f 72 69 74 68 6d 5d 0a 09 09 73 65  hAlgorithm]...se
1b90: 74 20 70 75 62 6c 69 63 4b 65 79 20 24 72 6f 77  t publicKey $row
1ba0: 28 70 75 62 6c 69 63 4b 65 79 29 0a 0a 09 09 73  (publicKey)....s
1bb0: 65 74 20 70 6c 61 69 6e 74 65 78 74 20 22 24 7b  et plaintext "${
1bc0: 73 61 6c 74 7d 7c 24 7b 70 75 62 6c 69 63 4b 65  salt}|${publicKe
1bd0: 79 7d 7c 24 7b 70 61 73 73 77 6f 72 64 7d 22 0a  y}|${password}".
1be0: 0a 09 09 73 77 69 74 63 68 20 2d 2d 20 24 68 61  ...switch -- $ha
1bf0: 73 68 41 6c 67 6f 72 69 74 68 6d 20 7b 0a 09 09  shAlgorithm {...
1c00: 09 22 73 68 61 32 35 36 22 20 7b 0a 09 09 09 09  ."sha256" {.....
1c10: 73 65 74 20 76 65 72 69 66 69 63 61 74 69 6f 6e  set verification
1c20: 48 61 73 68 20 5b 73 68 61 32 3a 3a 73 68 61 32  Hash [sha2::sha2
1c30: 35 36 20 2d 68 65 78 20 2d 2d 20 24 70 6c 61 69  56 -hex -- $plai
1c40: 6e 74 65 78 74 5d 0a 09 09 09 7d 0a 09 09 09 64  ntext]....}....d
1c50: 65 66 61 75 6c 74 20 7b 0a 09 09 09 09 72 65 74  efault {.....ret
1c60: 75 72 6e 20 2d 63 6f 64 65 20 65 72 72 6f 72 20  urn -code error 
1c70: 22 55 6e 6b 6e 6f 77 6e 20 68 61 73 68 69 6e 67  "Unknown hashing
1c80: 20 61 6c 67 6f 72 69 74 68 6d 3a 20 24 68 61 73   algorithm: $has
1c90: 68 41 6c 67 6f 72 69 74 68 6d 22 0a 09 09 09 7d  hAlgorithm"....}
1ca0: 0a 09 09 7d 0a 0a 09 09 73 65 74 20 72 6f 77 28  ...}....set row(
1cb0: 76 65 72 69 66 69 63 61 74 69 6f 6e 48 61 73 68  verificationHash
1cc0: 29 20 5b 64 69 63 74 20 67 65 74 20 24 72 6f 77  ) [dict get $row
1cd0: 28 76 65 72 69 66 69 63 61 74 69 6f 6e 29 20 68  (verification) h
1ce0: 61 73 68 5d 0a 0a 09 09 69 66 20 7b 24 76 65 72  ash]....if {$ver
1cf0: 69 66 69 63 61 74 69 6f 6e 48 61 73 68 20 6e 65  ificationHash ne
1d00: 20 24 72 6f 77 28 76 65 72 69 66 69 63 61 74 69   $row(verificati
1d10: 6f 6e 48 61 73 68 29 7d 20 7b 0a 09 09 09 70 75  onHash)} {....pu
1d20: 74 73 20 73 74 64 65 72 72 20 22 46 41 49 4c 45  ts stderr "FAILE
1d30: 44 3a 20 76 65 72 69 66 69 63 61 74 69 6f 6e 20  D: verification 
1d40: 66 61 69 6c 65 64 20 66 6f 72 20 24 6e 61 6d 65  failed for $name
1d50: 20 77 69 74 68 20 70 75 62 6c 69 63 20 6b 65 79   with public key
1d60: 20 24 70 75 62 6c 69 63 4b 65 79 20 2d 2d 20 69   $publicKey -- i
1d70: 74 20 77 69 6c 6c 20 6e 6f 74 20 67 65 74 20 74  t will not get t
1d80: 68 65 20 6e 65 77 20 70 61 73 73 77 6f 72 64 2e  he new password.
1d90: 22 0a 0a 09 09 09 63 6f 6e 74 69 6e 75 65 0a 09  ".....continue..
1da0: 09 7d 0a 0a 09 09 6c 61 70 70 65 6e 64 20 70 75  .}....lappend pu
1db0: 62 6c 69 63 4b 65 79 73 20 24 70 75 62 6c 69 63  blicKeys $public
1dc0: 4b 65 79 0a 09 7d 0a 0a 09 72 65 74 75 72 6e 20  Key..}...return 
1dd0: 24 70 75 62 6c 69 63 4b 65 79 73 0a 7d 0a 0a 70  $publicKeys.}..p
1de0: 72 6f 63 20 5f 61 64 64 50 61 73 73 77 6f 72 64  roc _addPassword
1df0: 20 7b 6e 61 6d 65 20 70 61 73 73 77 6f 72 64 20   {name password 
1e00: 70 75 62 6c 69 63 4b 65 79 73 7d 20 7b 0a 09 73  publicKeys} {..s
1e10: 65 74 20 66 64 20 5b 6f 70 65 6e 20 22 2f 64 65  et fd [open "/de
1e20: 76 2f 75 72 61 6e 64 6f 6d 22 20 72 5d 0a 09 66  v/urandom" r]..f
1e30: 63 6f 6e 66 69 67 75 72 65 20 24 66 64 20 2d 74  configure $fd -t
1e40: 72 61 6e 73 6c 61 74 69 6f 6e 20 62 69 6e 61 72  ranslation binar
1e50: 79 0a 0a 09 73 65 74 20 6b 65 79 53 69 7a 65 20  y...set keySize 
1e60: 31 36 0a 0a 09 23 20 50 61 64 20 74 68 65 20 70  16...# Pad the p
1e70: 61 73 73 77 6f 72 64 20 77 69 74 68 20 30 20 62  assword with 0 b
1e80: 79 74 65 73 20 75 6e 74 69 6c 20 69 74 20 69 73  ytes until it is
1e90: 20 61 20 6d 75 6c 74 69 70 6c 65 20 6f 66 20 74   a multiple of t
1ea0: 68 65 20 6b 65 79 20 73 69 7a 65 0a 09 73 65 74  he key size..set
1eb0: 20 62 6c 6f 63 6b 50 61 73 73 77 6f 72 64 20 24   blockPassword $
1ec0: 70 61 73 73 77 6f 72 64 0a 09 61 70 70 65 6e 64  password..append
1ed0: 20 62 6c 6f 63 6b 50 61 73 73 77 6f 72 64 20 5b   blockPassword [
1ee0: 73 74 72 69 6e 67 20 72 65 70 65 61 74 20 22 5c  string repeat "\
1ef0: 78 30 30 22 20 5b 65 78 70 72 20 7b 2d 5b 73 74  x00" [expr {-[st
1f00: 72 69 6e 67 20 6c 65 6e 67 74 68 20 24 70 61 73  ring length $pas
1f10: 73 77 6f 72 64 5d 20 25 20 24 6b 65 79 53 69 7a  sword] % $keySiz
1f20: 65 7d 5d 5d 0a 0a 09 64 62 20 74 72 61 6e 73 61  e}]]...db transa
1f30: 63 74 69 6f 6e 20 7b 0a 09 09 64 62 20 65 76 61  ction {...db eva
1f40: 6c 20 7b 44 45 4c 45 54 45 20 46 52 4f 4d 20 70  l {DELETE FROM p
1f50: 61 73 73 77 6f 72 64 73 20 57 48 45 52 45 20 6e  asswords WHERE n
1f60: 61 6d 65 20 3d 20 24 6e 61 6d 65 3b 7d 0a 0a 09  ame = $name;}...
1f70: 09 66 6f 72 65 61 63 68 20 70 75 62 6c 69 63 4b  .foreach publicK
1f80: 65 79 20 24 70 75 62 6c 69 63 4b 65 79 73 20 7b  ey $publicKeys {
1f90: 0a 09 09 09 73 65 74 20 6b 65 79 20 5b 72 65 61  ....set key [rea
1fa0: 64 20 24 66 64 20 24 6b 65 79 53 69 7a 65 5d 0a  d $fd $keySize].
1fb0: 09 09 09 69 66 20 7b 5b 73 74 72 69 6e 67 20 6c  ...if {[string l
1fc0: 65 6e 67 74 68 20 24 6b 65 79 5d 20 21 3d 20 24  ength $key] != $
1fd0: 6b 65 79 53 69 7a 65 7d 20 7b 0a 09 09 09 09 63  keySize} {.....c
1fe0: 6c 6f 73 65 20 24 66 64 0a 0a 09 09 09 09 72 65  lose $fd......re
1ff0: 74 75 72 6e 20 2d 63 6f 64 65 20 65 72 72 6f 72  turn -code error
2000: 20 22 45 52 52 4f 52 3a 20 53 68 6f 72 74 20 72   "ERROR: Short r
2010: 65 61 64 20 66 72 6f 6d 20 72 61 6e 64 6f 6d 20  ead from random 
2020: 64 65 76 69 63 65 22 0a 09 09 09 7d 0a 0a 09 09  device"....}....
2030: 09 73 65 74 20 73 61 6c 74 20 5b 72 65 61 64 20  .set salt [read 
2040: 24 66 64 20 24 6b 65 79 53 69 7a 65 5d 0a 09 09  $fd $keySize]...
2050: 09 73 65 74 20 73 61 6c 74 20 5b 62 69 6e 61 72  .set salt [binar
2060: 79 20 65 6e 63 6f 64 65 20 62 61 73 65 36 34 20  y encode base64 
2070: 24 73 61 6c 74 5d 0a 0a 09 09 09 73 65 74 20 70  $salt].....set p
2080: 75 62 6c 69 63 4b 65 79 49 74 65 6d 20 5b 3a 3a  ublicKeyItem [::
2090: 70 6b 69 3a 3a 70 6b 63 73 3a 3a 70 61 72 73 65  pki::pkcs::parse
20a0: 5f 70 75 62 6c 69 63 5f 6b 65 79 20 5b 62 69 6e  _public_key [bin
20b0: 61 72 79 20 64 65 63 6f 64 65 20 62 61 73 65 36  ary decode base6
20c0: 34 20 24 70 75 62 6c 69 63 4b 65 79 5d 5d 0a 0a  4 $publicKey]]..
20d0: 09 09 09 73 65 74 20 65 6e 63 72 79 70 74 65 64  ...set encrypted
20e0: 4b 65 79 20 5b 62 69 6e 61 72 79 20 65 6e 63 6f  Key [binary enco
20f0: 64 65 20 62 61 73 65 36 34 20 5b 3a 3a 70 6b 69  de base64 [::pki
2100: 3a 3a 65 6e 63 72 79 70 74 20 2d 70 75 62 20 2d  ::encrypt -pub -
2110: 62 69 6e 61 72 79 20 2d 2d 20 24 6b 65 79 20 24  binary -- $key $
2120: 70 75 62 6c 69 63 4b 65 79 49 74 65 6d 5d 5d 0a  publicKeyItem]].
2130: 0a 09 09 09 73 65 74 20 65 6e 63 72 79 70 74 65  ....set encrypte
2140: 64 50 61 73 73 20 5b 62 69 6e 61 72 79 20 65 6e  dPass [binary en
2150: 63 6f 64 65 20 62 61 73 65 36 34 20 5b 3a 3a 61  code base64 [::a
2160: 65 73 3a 3a 61 65 73 20 2d 64 69 72 20 65 6e 63  es::aes -dir enc
2170: 72 79 70 74 20 2d 6b 65 79 20 24 6b 65 79 20 2d  rypt -key $key -
2180: 2d 20 24 62 6c 6f 63 6b 50 61 73 73 77 6f 72 64  - $blockPassword
2190: 5d 5d 0a 0a 09 09 09 73 65 74 20 76 65 72 69 66  ]].....set verif
21a0: 69 63 61 74 69 6f 6e 48 61 73 68 20 5b 73 68 61  icationHash [sha
21b0: 32 3a 3a 73 68 61 32 35 36 20 2d 68 65 78 20 2d  2::sha256 -hex -
21c0: 2d 20 22 24 7b 73 61 6c 74 7d 7c 24 7b 70 75 62  - "${salt}|${pub
21d0: 6c 69 63 4b 65 79 7d 7c 24 7b 70 61 73 73 77 6f  licKey}|${passwo
21e0: 72 64 7d 22 5d 0a 09 09 09 73 65 74 20 76 65 72  rd}"]....set ver
21f0: 69 66 69 63 61 74 69 6f 6e 20 5b 6c 69 73 74 20  ification [list 
2200: 73 61 6c 74 20 24 73 61 6c 74 20 68 61 73 68 41  salt $salt hashA
2210: 6c 67 6f 72 69 74 68 6d 20 73 68 61 32 35 36 20  lgorithm sha256 
2220: 68 61 73 68 20 24 76 65 72 69 66 69 63 61 74 69  hash $verificati
2230: 6f 6e 48 61 73 68 5d 0a 0a 09 09 09 64 62 20 65  onHash].....db e
2240: 76 61 6c 20 7b 49 4e 53 45 52 54 20 49 4e 54 4f  val {INSERT INTO
2250: 20 70 61 73 73 77 6f 72 64 73 20 28 6e 61 6d 65   passwords (name
2260: 2c 20 65 6e 63 72 79 70 74 65 64 50 61 73 73 2c  , encryptedPass,
2270: 20 65 6e 63 72 79 70 74 65 64 4b 65 79 2c 20 70   encryptedKey, p
2280: 75 62 6c 69 63 4b 65 79 2c 20 76 65 72 69 66 69  ublicKey, verifi
2290: 63 61 74 69 6f 6e 29 20 56 41 4c 55 45 53 20 28  cation) VALUES (
22a0: 24 6e 61 6d 65 2c 20 40 65 6e 63 72 79 70 74 65  $name, @encrypte
22b0: 64 50 61 73 73 2c 20 40 65 6e 63 72 79 70 74 65  dPass, @encrypte
22c0: 64 4b 65 79 2c 20 40 70 75 62 6c 69 63 4b 65 79  dKey, @publicKey
22d0: 2c 20 40 76 65 72 69 66 69 63 61 74 69 6f 6e 29  , @verification)
22e0: 3b 7d 0a 09 09 7d 0a 09 7d 0a 0a 09 63 6c 6f 73  ;}...}..}...clos
22f0: 65 20 24 66 64 0a 7d 0a 0a 70 72 6f 63 20 5f 70  e $fd.}..proc _p
2300: 72 6f 6d 70 74 20 7b 70 72 6f 6d 70 74 7d 20 7b  rompt {prompt} {
2310: 0a 09 70 75 74 73 20 2d 6e 6f 6e 65 77 6c 69 6e  ..puts -nonewlin
2320: 65 20 24 70 72 6f 6d 70 74 0a 09 66 6c 75 73 68  e $prompt..flush
2330: 20 73 74 64 6f 75 74 0a 0a 09 70 75 74 73 20 2d   stdout...puts -
2340: 6e 6f 6e 65 77 6c 69 6e 65 20 5b 65 78 65 63 20  nonewline [exec 
2350: 73 74 74 79 20 2d 65 63 68 6f 5d 0a 09 66 6c 75  stty -echo]..flu
2360: 73 68 20 73 74 64 6f 75 74 0a 0a 09 73 65 74 20  sh stdout...set 
2370: 70 61 73 73 77 6f 72 64 20 5b 67 65 74 73 20 73  password [gets s
2380: 74 64 69 6e 5d 0a 0a 09 70 75 74 73 20 2d 6e 6f  tdin]...puts -no
2390: 6e 65 77 6c 69 6e 65 20 5b 65 78 65 63 20 73 74  newline [exec st
23a0: 74 79 20 65 63 68 6f 5d 0a 09 70 75 74 73 20 22  ty echo]..puts "
23b0: 22 0a 09 66 6c 75 73 68 20 73 74 64 6f 75 74 0a  "..flush stdout.
23c0: 0a 09 72 65 74 75 72 6e 20 24 70 61 73 73 77 6f  ..return $passwo
23d0: 72 64 0a 7d 0a 0a 70 72 6f 63 20 5f 67 65 74 50  rd.}..proc _getP
23e0: 61 73 73 77 6f 72 64 20 7b 6e 61 6d 65 7d 20 7b  assword {name} {
23f0: 0a 09 73 65 74 20 65 78 69 73 74 73 20 5b 64 62  ..set exists [db
2400: 20 65 76 61 6c 20 7b 53 45 4c 45 43 54 20 31 20   eval {SELECT 1 
2410: 46 52 4f 4d 20 70 61 73 73 77 6f 72 64 73 20 57  FROM passwords W
2420: 48 45 52 45 20 6e 61 6d 65 20 3d 20 24 6e 61 6d  HERE name = $nam
2430: 65 20 4c 49 4d 49 54 20 31 3b 7d 5d 0a 09 69 66  e LIMIT 1;}]..if
2440: 20 7b 24 65 78 69 73 74 73 20 21 3d 20 22 31 22   {$exists != "1"
2450: 7d 20 7b 0a 09 09 72 65 74 75 72 6e 20 2d 63 6f  } {...return -co
2460: 64 65 20 65 72 72 6f 72 20 22 50 61 73 73 77 6f  de error "Passwo
2470: 72 64 20 5c 22 24 6e 61 6d 65 5c 22 20 64 6f 65  rd \"$name\" doe
2480: 73 20 6e 6f 74 20 65 78 69 73 74 73 2e 22 0a 09  s not exists."..
2490: 7d 0a 0a 09 66 6f 72 65 61 63 68 20 73 6c 6f 74  }...foreach slot
24a0: 49 6e 66 6f 44 69 63 74 20 5b 5f 6c 69 73 74 43  InfoDict [_listC
24b0: 65 72 74 69 66 69 63 61 74 65 73 5d 20 7b 0a 09  ertificates] {..
24c0: 09 75 6e 73 65 74 20 2d 6e 6f 63 6f 6d 70 6c 61  .unset -nocompla
24d0: 69 6e 20 73 6c 6f 74 49 6e 66 6f 0a 09 09 61 72  in slotInfo...ar
24e0: 72 61 79 20 73 65 74 20 73 6c 6f 74 49 6e 66 6f  ray set slotInfo
24f0: 20 24 73 6c 6f 74 49 6e 66 6f 44 69 63 74 0a 0a   $slotInfoDict..
2500: 09 09 73 65 74 20 70 75 62 6b 65 79 20 24 73 6c  ..set pubkey $sl
2510: 6f 74 49 6e 66 6f 28 70 75 62 6b 65 79 29 0a 09  otInfo(pubkey)..
2520: 09 73 65 74 20 70 72 6f 6d 70 74 20 24 73 6c 6f  .set prompt $slo
2530: 74 49 6e 66 6f 28 70 72 6f 6d 70 74 29 0a 0a 09  tInfo(prompt)...
2540: 09 69 66 20 7b 5b 69 6e 66 6f 20 65 78 69 73 74  .if {[info exist
2550: 73 20 70 72 6f 6d 70 74 65 64 28 24 73 6c 6f 74  s prompted($slot
2560: 49 6e 66 6f 28 69 64 29 29 5d 7d 20 7b 0a 09 09  Info(id))]} {...
2570: 09 73 65 74 20 70 72 6f 6d 70 74 20 66 61 6c 73  .set prompt fals
2580: 65 0a 09 09 7d 0a 0a 09 09 69 66 20 7b 24 70 72  e...}....if {$pr
2590: 6f 6d 70 74 7d 20 7b 0a 09 09 09 73 65 74 20 50  ompt} {....set P
25a0: 49 4e 20 5b 5f 70 72 6f 6d 70 74 20 22 50 6c 65  IN [_prompt "Ple
25b0: 61 73 65 20 65 6e 74 65 72 20 74 68 65 20 50 49  ase enter the PI
25c0: 4e 20 66 6f 72 20 5b 64 69 63 74 20 67 65 74 20  N for [dict get 
25d0: 24 73 6c 6f 74 49 6e 66 6f 28 63 65 72 74 29 20  $slotInfo(cert) 
25e0: 73 75 62 6a 65 63 74 5d 3a 20 22 5d 0a 0a 09 09  subject]: "]....
25f0: 09 69 66 20 7b 21 5b 3a 3a 70 6b 69 3a 3a 70 6b  .if {![::pki::pk
2600: 63 73 31 31 3a 3a 6c 6f 67 69 6e 20 24 73 6c 6f  cs11::login $slo
2610: 74 49 6e 66 6f 28 68 61 6e 64 6c 65 29 20 24 73  tInfo(handle) $s
2620: 6c 6f 74 49 6e 66 6f 28 69 64 29 20 24 50 49 4e  lotInfo(id) $PIN
2630: 5d 7d 20 7b 0a 09 09 09 09 72 65 74 75 72 6e 20  ]} {.....return 
2640: 2d 63 6f 64 65 20 65 72 72 6f 72 20 22 55 6e 61  -code error "Una
2650: 62 6c 65 20 74 6f 20 61 75 74 68 65 6e 74 69 63  ble to authentic
2660: 61 74 65 22 0a 09 09 09 7d 0a 0a 09 09 09 73 65  ate"....}.....se
2670: 74 20 70 72 6f 6d 70 74 65 64 28 24 73 6c 6f 74  t prompted($slot
2680: 49 6e 66 6f 28 69 64 29 29 20 31 0a 09 09 7d 0a  Info(id)) 1...}.
2690: 0a 09 09 64 62 20 65 76 61 6c 20 7b 53 45 4c 45  ...db eval {SELE
26a0: 43 54 20 65 6e 63 72 79 70 74 65 64 50 61 73 73  CT encryptedPass
26b0: 2c 20 65 6e 63 72 79 70 74 65 64 4b 65 79 20 46  , encryptedKey F
26c0: 52 4f 4d 20 70 61 73 73 77 6f 72 64 73 20 57 48  ROM passwords WH
26d0: 45 52 45 20 6e 61 6d 65 20 3d 20 24 6e 61 6d 65  ERE name = $name
26e0: 20 41 4e 44 20 70 75 62 6c 69 63 4b 65 79 20 3d   AND publicKey =
26f0: 20 24 70 75 62 6b 65 79 3b 7d 20 72 6f 77 20 7b   $pubkey;} row {
2700: 0a 09 09 09 73 65 74 20 6b 65 79 20 5b 3a 3a 70  ....set key [::p
2710: 6b 69 3a 3a 64 65 63 72 79 70 74 20 2d 62 69 6e  ki::decrypt -bin
2720: 61 72 79 20 2d 70 72 69 76 20 2d 2d 20 5b 62 69  ary -priv -- [bi
2730: 6e 61 72 79 20 64 65 63 6f 64 65 20 62 61 73 65  nary decode base
2740: 36 34 20 24 72 6f 77 28 65 6e 63 72 79 70 74 65  64 $row(encrypte
2750: 64 4b 65 79 29 5d 20 24 73 6c 6f 74 49 6e 66 6f  dKey)] $slotInfo
2760: 28 63 65 72 74 29 5d 0a 09 09 09 73 65 74 20 70  (cert)]....set p
2770: 61 73 73 77 6f 72 64 20 5b 3a 3a 61 65 73 3a 3a  assword [::aes::
2780: 61 65 73 20 2d 64 69 72 20 64 65 63 72 79 70 74  aes -dir decrypt
2790: 20 2d 6b 65 79 20 24 6b 65 79 20 2d 2d 20 5b 62   -key $key -- [b
27a0: 69 6e 61 72 79 20 64 65 63 6f 64 65 20 62 61 73  inary decode bas
27b0: 65 36 34 20 24 72 6f 77 28 65 6e 63 72 79 70 74  e64 $row(encrypt
27c0: 65 64 50 61 73 73 29 5d 5d 0a 0a 09 09 09 72 65  edPass)]].....re
27d0: 74 75 72 6e 20 5b 73 74 72 69 6e 67 20 74 72 69  turn [string tri
27e0: 6d 72 69 67 68 74 20 24 70 61 73 73 77 6f 72 64  mright $password
27f0: 20 22 5c 78 30 30 22 5d 0a 09 09 7d 0a 09 7d 0a   "\x00"]...}..}.
2800: 0a 09 72 65 74 75 72 6e 20 2d 63 6f 64 65 20 65  ..return -code e
2810: 72 72 6f 72 20 22 4e 6f 20 76 61 6c 69 64 20 6b  rror "No valid k
2820: 65 79 73 22 0a 7d 0a 0a 70 72 6f 63 20 5f 6d 6f  eys".}..proc _mo
2830: 64 69 66 79 50 75 62 6c 69 63 4b 65 79 73 20 7b  difyPublicKeys {
2840: 70 61 73 73 77 6f 72 64 4e 61 6d 65 20 75 73 65  passwordName use
2850: 72 4e 61 6d 65 73 20 73 71 6c 7d 20 7b 0a 09 73  rNames sql} {..s
2860: 65 74 20 65 78 69 73 74 73 20 5b 64 62 20 65 76  et exists [db ev
2870: 61 6c 20 7b 53 45 4c 45 43 54 20 31 20 46 52 4f  al {SELECT 1 FRO
2880: 4d 20 70 61 73 73 77 6f 72 64 73 20 57 48 45 52  M passwords WHER
2890: 45 20 6e 61 6d 65 20 3d 20 24 70 61 73 73 77 6f  E name = $passwo
28a0: 72 64 4e 61 6d 65 20 4c 49 4d 49 54 20 31 3b 7d  rdName LIMIT 1;}
28b0: 5d 0a 09 69 66 20 7b 24 65 78 69 73 74 73 20 21  ]..if {$exists !
28c0: 3d 20 22 31 22 7d 20 7b 0a 09 09 72 65 74 75 72  = "1"} {...retur
28d0: 6e 20 2d 63 6f 64 65 20 65 72 72 6f 72 20 22 50  n -code error "P
28e0: 61 73 73 77 6f 72 64 20 5c 22 24 70 61 73 73 77  assword \"$passw
28f0: 6f 72 64 4e 61 6d 65 5c 22 20 64 6f 65 73 20 6e  ordName\" does n
2900: 6f 74 20 65 78 69 73 74 73 2e 22 0a 09 7d 0a 0a  ot exists."..}..
2910: 09 73 65 74 20 70 75 62 6c 69 63 4b 65 79 73 20  .set publicKeys 
2920: 5b 6c 69 73 74 5d 0a 0a 09 64 62 20 65 76 61 6c  [list]...db eval
2930: 20 7b 53 45 4c 45 43 54 20 70 75 62 6c 69 63 4b   {SELECT publicK
2940: 65 79 20 46 52 4f 4d 20 70 61 73 73 77 6f 72 64  ey FROM password
2950: 73 20 57 48 45 52 45 20 6e 61 6d 65 20 3d 20 24  s WHERE name = $
2960: 70 61 73 73 77 6f 72 64 4e 61 6d 65 3b 7d 20 72  passwordName;} r
2970: 6f 77 20 7b 0a 09 09 6c 61 70 70 65 6e 64 20 70  ow {...lappend p
2980: 75 62 6c 69 63 4b 65 79 73 20 24 72 6f 77 28 70  ublicKeys $row(p
2990: 75 62 6c 69 63 4b 65 79 29 0a 09 7d 0a 0a 09 73  ublicKey)..}...s
29a0: 65 74 20 63 68 61 6e 67 65 52 65 71 75 69 72 65  et changeRequire
29b0: 64 20 30 0a 09 66 6f 72 65 61 63 68 20 75 73 65  d 0..foreach use
29c0: 72 20 24 75 73 65 72 4e 61 6d 65 73 20 7b 0a 09  r $userNames {..
29d0: 09 75 6e 73 65 74 20 2d 6e 6f 63 6f 6d 70 6c 61  .unset -nocompla
29e0: 69 6e 20 72 6f 77 0a 09 09 64 62 20 65 76 61 6c  in row...db eval
29f0: 20 7b 53 45 4c 45 43 54 20 70 75 62 6c 69 63 4b   {SELECT publicK
2a00: 65 79 20 46 52 4f 4d 20 75 73 65 72 73 20 57 48  ey FROM users WH
2a10: 45 52 45 20 6e 61 6d 65 20 3d 20 24 75 73 65 72  ERE name = $user
2a20: 3b 7d 20 72 6f 77 20 24 73 71 6c 0a 09 7d 0a 0a  ;} row $sql..}..
2a30: 09 69 66 20 7b 21 24 63 68 61 6e 67 65 52 65 71  .if {!$changeReq
2a40: 75 69 72 65 64 7d 20 7b 0a 09 09 72 65 74 75 72  uired} {...retur
2a50: 6e 0a 09 7d 0a 0a 09 73 65 74 20 70 61 73 73 77  n..}...set passw
2a60: 6f 72 64 20 5b 5f 67 65 74 50 61 73 73 77 6f 72  ord [_getPasswor
2a70: 64 20 24 70 61 73 73 77 6f 72 64 4e 61 6d 65 5d  d $passwordName]
2a80: 0a 0a 09 5f 61 64 64 50 61 73 73 77 6f 72 64 20  ..._addPassword 
2a90: 24 70 61 73 73 77 6f 72 64 4e 61 6d 65 20 24 70  $passwordName $p
2aa0: 61 73 73 77 6f 72 64 20 24 70 75 62 6c 69 63 4b  assword $publicK
2ab0: 65 79 73 0a 7d 0a 0a 70 72 6f 63 20 5f 67 65 74  eys.}..proc _get
2ac0: 55 73 65 72 73 46 6f 72 50 61 73 73 77 6f 72 64  UsersForPassword
2ad0: 20 7b 70 61 73 73 77 6f 72 64 4e 61 6d 65 73 7d   {passwordNames}
2ae0: 20 7b 0a 09 73 65 74 20 75 73 65 72 4e 61 6d 65   {..set userName
2af0: 73 20 5b 6c 69 73 74 5d 0a 0a 09 66 6f 72 65 61  s [list]...forea
2b00: 63 68 20 70 61 73 73 77 6f 72 64 4e 61 6d 65 20  ch passwordName 
2b10: 24 70 61 73 73 77 6f 72 64 4e 61 6d 65 73 20 7b  $passwordNames {
2b20: 0a 09 09 64 62 20 65 76 61 6c 20 7b 53 45 4c 45  ...db eval {SELE
2b30: 43 54 20 70 75 62 6c 69 63 4b 65 79 20 46 52 4f  CT publicKey FRO
2b40: 4d 20 70 61 73 73 77 6f 72 64 73 20 57 48 45 52  M passwords WHER
2b50: 45 20 6e 61 6d 65 20 3d 20 24 70 61 73 73 77 6f  E name = $passwo
2b60: 72 64 4e 61 6d 65 3b 7d 20 70 61 73 73 77 6f 72  rdName;} passwor
2b70: 64 52 6f 77 20 7b 0a 09 09 09 64 62 20 65 76 61  dRow {....db eva
2b80: 6c 20 7b 53 45 4c 45 43 54 20 6e 61 6d 65 20 46  l {SELECT name F
2b90: 52 4f 4d 20 75 73 65 72 73 20 57 48 45 52 45 20  ROM users WHERE 
2ba0: 70 75 62 6c 69 63 4b 65 79 20 3d 20 24 70 61 73  publicKey = $pas
2bb0: 73 77 6f 72 64 52 6f 77 28 70 75 62 6c 69 63 4b  swordRow(publicK
2bc0: 65 79 29 7d 20 75 73 65 72 52 6f 77 20 7b 0a 09  ey)} userRow {..
2bd0: 09 09 09 69 66 20 7b 24 75 73 65 72 52 6f 77 28  ...if {$userRow(
2be0: 6e 61 6d 65 29 20 69 6e 20 24 75 73 65 72 4e 61  name) in $userNa
2bf0: 6d 65 73 7d 20 7b 0a 09 09 09 09 09 63 6f 6e 74  mes} {......cont
2c00: 69 6e 75 65 0a 09 09 09 09 7d 0a 0a 09 09 09 09  inue.....}......
2c10: 6c 61 70 70 65 6e 64 20 75 73 65 72 4e 61 6d 65  lappend userName
2c20: 73 20 24 75 73 65 72 52 6f 77 28 6e 61 6d 65 29  s $userRow(name)
2c30: 0a 09 09 09 7d 0a 09 09 7d 0a 09 7d 0a 0a 09 72  ....}...}..}...r
2c40: 65 74 75 72 6e 20 24 75 73 65 72 4e 61 6d 65 73  eturn $userNames
2c50: 0a 7d 0a 0a 70 72 6f 63 20 5f 67 65 74 50 61 73  .}..proc _getPas
2c60: 73 77 6f 72 64 73 46 6f 72 55 73 65 72 20 7b 75  swordsForUser {u
2c70: 73 65 72 4e 61 6d 65 73 7d 20 7b 0a 09 73 65 74  serNames} {..set
2c80: 20 70 61 73 73 77 6f 72 64 4e 61 6d 65 73 20 5b   passwordNames [
2c90: 6c 69 73 74 5d 0a 0a 09 66 6f 72 65 61 63 68 20  list]...foreach 
2ca0: 75 73 65 72 4e 61 6d 65 20 24 75 73 65 72 4e 61  userName $userNa
2cb0: 6d 65 73 20 7b 0a 09 09 64 62 20 65 76 61 6c 20  mes {...db eval 
2cc0: 7b 53 45 4c 45 43 54 20 70 75 62 6c 69 63 4b 65  {SELECT publicKe
2cd0: 79 20 46 52 4f 4d 20 75 73 65 72 73 20 57 48 45  y FROM users WHE
2ce0: 52 45 20 6e 61 6d 65 20 3d 20 24 75 73 65 72 4e  RE name = $userN
2cf0: 61 6d 65 3b 7d 20 75 73 65 72 52 6f 77 20 7b 0a  ame;} userRow {.
2d00: 09 09 09 64 62 20 65 76 61 6c 20 7b 53 45 4c 45  ...db eval {SELE
2d10: 43 54 20 6e 61 6d 65 20 46 52 4f 4d 20 70 61 73  CT name FROM pas
2d20: 73 77 6f 72 64 73 20 57 48 45 52 45 20 70 75 62  swords WHERE pub
2d30: 6c 69 63 4b 65 79 20 3d 20 24 75 73 65 72 52 6f  licKey = $userRo
2d40: 77 28 70 75 62 6c 69 63 4b 65 79 29 7d 20 70 61  w(publicKey)} pa
2d50: 73 73 77 6f 72 64 52 6f 77 20 7b 0a 09 09 09 09  sswordRow {.....
2d60: 69 66 20 7b 24 70 61 73 73 77 6f 72 64 52 6f 77  if {$passwordRow
2d70: 28 6e 61 6d 65 29 20 69 6e 20 24 70 61 73 73 77  (name) in $passw
2d80: 6f 72 64 4e 61 6d 65 73 7d 20 7b 0a 09 09 09 09  ordNames} {.....
2d90: 09 63 6f 6e 74 69 6e 75 65 0a 09 09 09 09 7d 0a  .continue.....}.
2da0: 0a 09 09 09 09 6c 61 70 70 65 6e 64 20 70 61 73  .....lappend pas
2db0: 73 77 6f 72 64 4e 61 6d 65 73 20 24 70 61 73 73  swordNames $pass
2dc0: 77 6f 72 64 52 6f 77 28 6e 61 6d 65 29 0a 09 09  wordRow(name)...
2dd0: 09 7d 0a 09 09 7d 0a 09 7d 0a 0a 09 72 65 74 75  .}...}..}...retu
2de0: 72 6e 20 24 70 61 73 73 77 6f 72 64 4e 61 6d 65  rn $passwordName
2df0: 73 0a 7d 0a 23 20 45 6e 64 20 69 6e 74 65 72 6e  s.}.# End intern
2e00: 61 6c 20 66 75 6e 63 74 69 6f 6e 73 0a 0a 23 20  al functions..# 
2e10: 53 74 61 72 74 20 75 73 65 72 20 43 4c 49 20 66  Start user CLI f
2e20: 75 6e 63 74 69 6f 6e 73 0a 70 72 6f 63 20 6c 69  unctions.proc li
2e30: 73 74 4c 6f 63 61 6c 4b 65 79 73 20 7b 7d 20 7b  stLocalKeys {} {
2e40: 0a 09 66 6f 72 65 61 63 68 20 73 6c 6f 74 49 6e  ..foreach slotIn
2e50: 66 6f 44 69 63 74 20 5b 5f 6c 69 73 74 43 65 72  foDict [_listCer
2e60: 74 69 66 69 63 61 74 65 73 5d 20 7b 0a 09 09 75  tificates] {...u
2e70: 6e 73 65 74 20 2d 6e 6f 63 6f 6d 70 6c 61 69 6e  nset -nocomplain
2e80: 20 73 6c 6f 74 49 6e 66 6f 0a 09 09 61 72 72 61   slotInfo...arra
2e90: 79 20 73 65 74 20 73 6c 6f 74 49 6e 66 6f 20 24  y set slotInfo $
2ea0: 73 6c 6f 74 49 6e 66 6f 44 69 63 74 0a 0a 09 09  slotInfoDict....
2eb0: 73 65 74 20 73 75 62 6a 65 63 74 20 5b 64 69 63  set subject [dic
2ec0: 74 20 67 65 74 20 24 73 6c 6f 74 49 6e 66 6f 28  t get $slotInfo(
2ed0: 63 65 72 74 29 20 73 75 62 6a 65 63 74 5d 0a 09  cert) subject]..
2ee0: 09 73 65 74 20 70 75 62 6b 65 79 20 20 24 73 6c  .set pubkey  $sl
2ef0: 6f 74 49 6e 66 6f 28 70 75 62 6b 65 79 29 0a 0a  otInfo(pubkey)..
2f00: 09 09 6c 61 70 70 65 6e 64 20 70 75 62 6c 69 63  ..lappend public
2f10: 4b 65 79 73 28 24 73 75 62 6a 65 63 74 29 20 24  Keys($subject) $
2f20: 70 75 62 6b 65 79 0a 09 7d 0a 0a 09 66 6f 72 65  pubkey..}...fore
2f30: 61 63 68 20 7b 73 75 62 6a 65 63 74 20 70 75 62  ach {subject pub
2f40: 6b 65 79 73 7d 20 5b 61 72 72 61 79 20 67 65 74  keys} [array get
2f50: 20 70 75 62 6c 69 63 4b 65 79 73 5d 20 7b 0a 09   publicKeys] {..
2f60: 09 70 75 74 73 20 22 24 73 75 62 6a 65 63 74 22  .puts "$subject"
2f70: 0a 0a 09 09 66 6f 72 65 61 63 68 20 70 75 62 6b  ....foreach pubk
2f80: 65 79 20 24 70 75 62 6b 65 79 73 20 7b 0a 09 09  ey $pubkeys {...
2f90: 09 70 75 74 73 20 22 20 20 7c 2d 3e 20 24 70 75  .puts "  |-> $pu
2fa0: 62 6b 65 79 22 0a 09 09 7d 0a 09 7d 0a 7d 0a 0a  bkey"...}..}.}..
2fb0: 70 72 6f 63 20 6c 69 73 74 41 76 61 69 6c 61 62  proc listAvailab
2fc0: 6c 65 50 61 73 73 77 6f 72 64 73 20 7b 7d 20 7b  lePasswords {} {
2fd0: 0a 09 73 65 74 20 70 61 73 73 77 6f 72 64 4e 61  ..set passwordNa
2fe0: 6d 65 73 20 5b 6c 69 73 74 5d 0a 09 66 6f 72 65  mes [list]..fore
2ff0: 61 63 68 20 73 6c 6f 74 49 6e 66 6f 44 69 63 74  ach slotInfoDict
3000: 20 5b 5f 6c 69 73 74 43 65 72 74 69 66 69 63 61   [_listCertifica
3010: 74 65 73 5d 20 7b 0a 09 09 75 6e 73 65 74 20 2d  tes] {...unset -
3020: 6e 6f 63 6f 6d 70 6c 61 69 6e 20 73 6c 6f 74 49  nocomplain slotI
3030: 6e 66 6f 0a 09 09 61 72 72 61 79 20 73 65 74 20  nfo...array set 
3040: 73 6c 6f 74 49 6e 66 6f 20 24 73 6c 6f 74 49 6e  slotInfo $slotIn
3050: 66 6f 44 69 63 74 0a 0a 09 09 73 65 74 20 70 75  foDict....set pu
3060: 62 6b 65 79 20 24 73 6c 6f 74 49 6e 66 6f 28 70  bkey $slotInfo(p
3070: 75 62 6b 65 79 29 0a 0a 09 09 75 6e 73 65 74 20  ubkey)....unset 
3080: 2d 6e 6f 63 6f 6d 70 6c 61 69 6e 20 72 6f 77 0a  -nocomplain row.
3090: 09 09 64 62 20 65 76 61 6c 20 7b 53 45 4c 45 43  ..db eval {SELEC
30a0: 54 20 6e 61 6d 65 20 46 52 4f 4d 20 70 61 73 73  T name FROM pass
30b0: 77 6f 72 64 73 20 57 48 45 52 45 20 70 75 62 6c  words WHERE publ
30c0: 69 63 4b 65 79 20 3d 20 24 70 75 62 6b 65 79 3b  icKey = $pubkey;
30d0: 7d 20 72 6f 77 20 7b 0a 09 09 09 69 66 20 7b 24  } row {....if {$
30e0: 72 6f 77 28 6e 61 6d 65 29 20 69 6e 20 24 70 61  row(name) in $pa
30f0: 73 73 77 6f 72 64 4e 61 6d 65 73 7d 20 7b 0a 09  sswordNames} {..
3100: 09 09 09 63 6f 6e 74 69 6e 75 65 0a 09 09 09 7d  ...continue....}
3110: 0a 0a 09 09 09 6c 61 70 70 65 6e 64 20 70 61 73  .....lappend pas
3120: 73 77 6f 72 64 4e 61 6d 65 73 20 24 72 6f 77 28  swordNames $row(
3130: 6e 61 6d 65 29 0a 09 09 7d 0a 09 7d 0a 0a 0a 09  name)...}..}....
3140: 66 6f 72 65 61 63 68 20 70 61 73 73 77 6f 72 64  foreach password
3150: 4e 61 6d 65 20 24 70 61 73 73 77 6f 72 64 4e 61  Name $passwordNa
3160: 6d 65 73 20 7b 0a 09 09 70 75 74 73 20 22 24 70  mes {...puts "$p
3170: 61 73 73 77 6f 72 64 4e 61 6d 65 20 2d 20 5b 6a  asswordName - [j
3180: 6f 69 6e 20 5b 5f 67 65 74 55 73 65 72 73 46 6f  oin [_getUsersFo
3190: 72 50 61 73 73 77 6f 72 64 20 5b 6c 69 73 74 20  rPassword [list 
31a0: 24 70 61 73 73 77 6f 72 64 4e 61 6d 65 5d 5d 20  $passwordName]] 
31b0: 7b 2c 20 7d 5d 22 0a 09 7d 0a 7d 0a 0a 70 72 6f  {, }]"..}.}..pro
31c0: 63 20 6c 69 73 74 50 61 73 73 77 6f 72 64 73 20  c listPasswords 
31d0: 7b 7d 20 7b 0a 09 64 62 20 65 76 61 6c 20 7b 53  {} {..db eval {S
31e0: 45 4c 45 43 54 20 44 49 53 54 49 4e 43 54 20 6e  ELECT DISTINCT n
31f0: 61 6d 65 20 46 52 4f 4d 20 70 61 73 73 77 6f 72  ame FROM passwor
3200: 64 73 3b 7d 20 72 6f 77 20 7b 0a 09 09 70 75 74  ds;} row {...put
3210: 73 20 22 24 72 6f 77 28 6e 61 6d 65 29 20 2d 20  s "$row(name) - 
3220: 5b 6a 6f 69 6e 20 5b 5f 67 65 74 55 73 65 72 73  [join [_getUsers
3230: 46 6f 72 50 61 73 73 77 6f 72 64 20 5b 6c 69 73  ForPassword [lis
3240: 74 20 24 72 6f 77 28 6e 61 6d 65 29 5d 5d 20 7b  t $row(name)]] {
3250: 2c 20 7d 5d 22 0a 09 7d 0a 7d 0a 0a 70 72 6f 63  , }]"..}.}..proc
3260: 20 6c 69 73 74 55 73 65 72 73 20 7b 7d 20 7b 0a   listUsers {} {.
3270: 09 64 62 20 65 76 61 6c 20 7b 53 45 4c 45 43 54  .db eval {SELECT
3280: 20 44 49 53 54 49 4e 43 54 20 6e 61 6d 65 20 46   DISTINCT name F
3290: 52 4f 4d 20 75 73 65 72 73 3b 7d 20 72 6f 77 20  ROM users;} row 
32a0: 7b 0a 09 09 70 75 74 73 20 22 24 72 6f 77 28 6e  {...puts "$row(n
32b0: 61 6d 65 29 20 2d 20 5b 6a 6f 69 6e 20 5b 5f 67  ame) - [join [_g
32c0: 65 74 50 61 73 73 77 6f 72 64 73 46 6f 72 55 73  etPasswordsForUs
32d0: 65 72 20 5b 6c 69 73 74 20 24 72 6f 77 28 6e 61  er [list $row(na
32e0: 6d 65 29 5d 5d 20 7b 2c 20 7d 5d 22 0a 09 7d 0a  me)]] {, }]"..}.
32f0: 7d 0a 0a 70 72 6f 63 20 61 64 64 55 73 65 72 20  }..proc addUser 
3300: 7b 75 73 65 72 4e 61 6d 65 20 6b 65 79 7d 20 7b  {userName key} {
3310: 0a 09 73 65 74 20 6b 65 79 52 61 77 20 5b 62 69  ..set keyRaw [bi
3320: 6e 61 72 79 20 64 65 63 6f 64 65 20 62 61 73 65  nary decode base
3330: 36 34 20 24 6b 65 79 5d 0a 09 73 65 74 20 6b 65  64 $key]..set ke
3340: 79 56 65 72 69 66 79 20 5b 3a 3a 70 6b 69 3a 3a  yVerify [::pki::
3350: 70 6b 63 73 3a 3a 70 61 72 73 65 5f 70 75 62 6c  pkcs::parse_publ
3360: 69 63 5f 6b 65 79 20 24 6b 65 79 52 61 77 5d 0a  ic_key $keyRaw].
3370: 0a 09 64 62 20 65 76 61 6c 20 7b 49 4e 53 45 52  ..db eval {INSER
3380: 54 20 49 4e 54 4f 20 75 73 65 72 73 20 28 6e 61  T INTO users (na
3390: 6d 65 2c 20 70 75 62 6c 69 63 4b 65 79 29 20 56  me, publicKey) V
33a0: 41 4c 55 45 53 20 28 24 75 73 65 72 4e 61 6d 65  ALUES ($userName
33b0: 2c 20 40 6b 65 79 29 3b 7d 0a 0a 09 23 20 58 58  , @key);}...# XX
33c0: 58 3a 54 4f 44 4f 3a 47 6f 20 74 68 72 6f 75 67  X:TODO:Go throug
33d0: 68 20 61 6e 64 20 72 65 2d 61 75 74 68 6f 72 69  h and re-authori
33e0: 7a 65 20 69 66 20 70 6f 73 73 69 62 6c 65 0a 7d  ze if possible.}
33f0: 0a 0a 70 72 6f 63 20 64 65 6c 65 74 65 55 73 65  ..proc deleteUse
3400: 72 20 7b 75 73 65 72 4e 61 6d 65 7d 20 7b 0a 09  r {userName} {..
3410: 23 20 58 58 58 3a 54 4f 44 4f 3a 20 47 6f 20 74  # XXX:TODO: Go t
3420: 68 72 6f 75 67 68 20 61 6e 64 20 64 65 2d 61 75  hrough and de-au
3430: 74 68 6f 72 69 7a 65 0a 7d 0a 0a 70 72 6f 63 20  thorize.}..proc 
3440: 61 64 64 50 61 73 73 77 6f 72 64 20 7b 70 61 73  addPassword {pas
3450: 73 77 6f 72 64 4e 61 6d 65 20 70 61 73 73 77 6f  swordName passwo
3460: 72 64 20 61 72 67 73 7d 20 7b 0a 09 73 65 74 20  rd args} {..set 
3470: 69 6e 69 74 69 61 6c 55 73 65 72 73 20 24 61 72  initialUsers $ar
3480: 67 73 0a 0a 09 69 66 20 7b 24 70 61 73 73 77 6f  gs...if {$passwo
3490: 72 64 20 65 71 20 22 22 7d 20 7b 0a 09 09 73 65  rd eq ""} {...se
34a0: 74 20 70 61 73 73 77 6f 72 64 20 5b 5f 70 72 6f  t password [_pro
34b0: 6d 70 74 20 22 50 6c 65 61 73 65 20 65 6e 74 65  mpt "Please ente
34c0: 72 20 74 68 65 20 6e 65 77 20 70 61 73 73 77 6f  r the new passwo
34d0: 72 64 3a 20 22 5d 0a 09 7d 0a 0a 09 23 20 56 65  rd: "]..}...# Ve
34e0: 72 69 66 79 20 74 68 61 74 20 74 68 69 73 20 70  rify that this p
34f0: 61 73 73 77 6f 72 64 20 64 6f 65 73 20 6e 6f 74  assword does not
3500: 20 61 6c 72 65 61 64 79 20 65 78 69 73 74 0a 09   already exist..
3510: 73 65 74 20 65 78 69 73 74 73 20 5b 64 62 20 65  set exists [db e
3520: 76 61 6c 20 7b 53 45 4c 45 43 54 20 31 20 46 52  val {SELECT 1 FR
3530: 4f 4d 20 70 61 73 73 77 6f 72 64 73 20 57 48 45  OM passwords WHE
3540: 52 45 20 6e 61 6d 65 20 3d 20 24 70 61 73 73 77  RE name = $passw
3550: 6f 72 64 4e 61 6d 65 20 4c 49 4d 49 54 20 31 3b  ordName LIMIT 1;
3560: 7d 5d 0a 09 69 66 20 7b 24 65 78 69 73 74 73 20  }]..if {$exists 
3570: 3d 3d 20 22 31 22 7d 20 7b 0a 09 09 72 65 74 75  == "1"} {...retu
3580: 72 6e 20 2d 63 6f 64 65 20 65 72 72 6f 72 20 22  rn -code error "
3590: 50 61 73 73 77 6f 72 64 20 5c 22 24 70 61 73 73  Password \"$pass
35a0: 77 6f 72 64 4e 61 6d 65 5c 22 20 61 6c 72 65 61  wordName\" alrea
35b0: 64 79 20 65 78 69 73 74 73 2c 20 63 61 6e 6e 6f  dy exists, canno
35c0: 74 20 61 64 64 2e 22 0a 09 7d 0a 0a 09 23 20 47  t add."..}...# G
35d0: 65 74 20 6b 65 79 73 20 66 6f 72 20 69 6e 69 74  et keys for init
35e0: 69 61 6c 20 75 73 65 72 73 0a 09 73 65 74 20 70  ial users..set p
35f0: 75 62 6c 69 63 4b 65 79 73 20 5b 6c 69 73 74 5d  ublicKeys [list]
3600: 0a 09 66 6f 72 65 61 63 68 20 75 73 65 72 20 24  ..foreach user $
3610: 69 6e 69 74 69 61 6c 55 73 65 72 73 20 7b 0a 09  initialUsers {..
3620: 09 75 6e 73 65 74 20 2d 6e 6f 63 6f 6d 70 6c 61  .unset -nocompla
3630: 69 6e 20 72 6f 77 0a 09 09 64 62 20 65 76 61 6c  in row...db eval
3640: 20 7b 53 45 4c 45 43 54 20 70 75 62 6c 69 63 4b   {SELECT publicK
3650: 65 79 20 46 52 4f 4d 20 75 73 65 72 73 20 57 48  ey FROM users WH
3660: 45 52 45 20 6e 61 6d 65 20 3d 20 24 75 73 65 72  ERE name = $user
3670: 3b 7d 20 72 6f 77 20 7b 0a 09 09 09 6c 61 70 70  ;} row {....lapp
3680: 65 6e 64 20 70 75 62 6c 69 63 4b 65 79 73 20 24  end publicKeys $
3690: 72 6f 77 28 70 75 62 6c 69 63 4b 65 79 29 0a 09  row(publicKey)..
36a0: 09 7d 0a 09 7d 0a 0a 09 5f 61 64 64 50 61 73 73  .}..}..._addPass
36b0: 77 6f 72 64 20 24 70 61 73 73 77 6f 72 64 4e 61  word $passwordNa
36c0: 6d 65 20 24 70 61 73 73 77 6f 72 64 20 24 70 75  me $password $pu
36d0: 62 6c 69 63 4b 65 79 73 0a 7d 0a 0a 70 72 6f 63  blicKeys.}..proc
36e0: 20 67 65 74 50 61 73 73 77 6f 72 64 20 7b 70 61   getPassword {pa
36f0: 73 73 77 6f 72 64 4e 61 6d 65 7d 20 7b 0a 09 70  sswordName} {..p
3700: 75 74 73 20 5b 5f 67 65 74 50 61 73 73 77 6f 72  uts [_getPasswor
3710: 64 20 24 70 61 73 73 77 6f 72 64 4e 61 6d 65 5d  d $passwordName]
3720: 0a 7d 0a 0a 70 72 6f 63 20 75 70 64 61 74 65 50  .}..proc updateP
3730: 61 73 73 77 6f 72 64 20 7b 70 61 73 73 77 6f 72  assword {passwor
3740: 64 4e 61 6d 65 20 70 61 73 73 77 6f 72 64 7d 20  dName password} 
3750: 7b 0a 09 69 66 20 7b 24 70 61 73 73 77 6f 72 64  {..if {$password
3760: 20 65 71 20 22 22 7d 20 7b 0a 09 09 73 65 74 20   eq ""} {...set 
3770: 70 61 73 73 77 6f 72 64 20 5b 5f 70 72 6f 6d 70  password [_promp
3780: 74 20 22 50 6c 65 61 73 65 20 65 6e 74 65 72 20  t "Please enter 
3790: 74 68 65 20 6e 65 77 20 70 61 73 73 77 6f 72 64  the new password
37a0: 3a 20 22 5d 0a 09 7d 0a 0a 09 73 65 74 20 6f 6c  : "]..}...set ol
37b0: 64 50 61 73 73 77 6f 72 64 20 5b 5f 67 65 74 50  dPassword [_getP
37c0: 61 73 73 77 6f 72 64 20 24 70 61 73 73 77 6f 72  assword $passwor
37d0: 64 4e 61 6d 65 5d 0a 0a 09 73 65 74 20 70 75 62  dName]...set pub
37e0: 6c 69 63 4b 65 79 73 20 5b 5f 76 65 72 69 66 79  licKeys [_verify
37f0: 50 61 73 73 77 6f 72 64 20 24 70 61 73 73 77 6f  Password $passwo
3800: 72 64 4e 61 6d 65 20 24 6f 6c 64 50 61 73 73 77  rdName $oldPassw
3810: 6f 72 64 5d 0a 0a 09 69 66 20 7b 5b 6c 6c 65 6e  ord]...if {[llen
3820: 67 74 68 20 24 70 75 62 6c 69 63 4b 65 79 73 5d  gth $publicKeys]
3830: 20 3d 3d 20 30 7d 20 7b 0a 09 09 70 75 74 73 20   == 0} {...puts 
3840: 73 74 64 65 72 72 20 22 57 61 72 6e 69 6e 67 3a  stderr "Warning:
3850: 20 54 68 69 73 20 77 69 6c 6c 20 64 65 6c 65 74   This will delet
3860: 65 20 74 68 65 20 70 61 73 73 77 6f 72 64 20 73  e the password s
3870: 69 6e 63 65 20 74 68 65 72 65 20 61 72 65 20 6e  ince there are n
3880: 6f 20 76 61 6c 69 64 20 70 75 62 6c 69 63 20 6b  o valid public k
3890: 65 79 73 2e 22 0a 09 7d 0a 0a 09 5f 61 64 64 50  eys."..}..._addP
38a0: 61 73 73 77 6f 72 64 20 24 70 61 73 73 77 6f 72  assword $passwor
38b0: 64 4e 61 6d 65 20 24 70 61 73 73 77 6f 72 64 20  dName $password 
38c0: 24 70 75 62 6c 69 63 4b 65 79 73 0a 7d 0a 0a 70  $publicKeys.}..p
38d0: 72 6f 63 20 64 65 6c 65 74 65 50 61 73 73 77 6f  roc deletePasswo
38e0: 72 64 20 7b 70 61 73 73 77 6f 72 64 4e 61 6d 65  rd {passwordName
38f0: 7d 20 7b 0a 09 64 62 20 65 76 61 6c 20 7b 44 45  } {..db eval {DE
3900: 4c 45 54 45 20 46 52 4f 4d 20 70 61 73 73 77 6f  LETE FROM passwo
3910: 72 64 73 20 57 48 45 52 45 20 6e 61 6d 65 20 3d  rds WHERE name =
3920: 20 24 70 61 73 73 77 6f 72 64 4e 61 6d 65 3b 7d   $passwordName;}
3930: 0a 7d 0a 0a 70 72 6f 63 20 61 75 74 68 6f 72 69  .}..proc authori
3940: 7a 65 55 73 65 72 73 20 7b 70 61 73 73 77 6f 72  zeUsers {passwor
3950: 64 4e 61 6d 65 20 61 72 67 73 7d 20 7b 0a 09 73  dName args} {..s
3960: 65 74 20 75 73 65 72 73 20 24 61 72 67 73 0a 0a  et users $args..
3970: 09 5f 6d 6f 64 69 66 79 50 75 62 6c 69 63 4b 65  ._modifyPublicKe
3980: 79 73 20 24 70 61 73 73 77 6f 72 64 4e 61 6d 65  ys $passwordName
3990: 20 24 75 73 65 72 73 20 7b 0a 09 09 69 66 20 7b   $users {...if {
39a0: 24 72 6f 77 28 70 75 62 6c 69 63 4b 65 79 29 20  $row(publicKey) 
39b0: 69 6e 20 24 70 75 62 6c 69 63 4b 65 79 73 7d 20  in $publicKeys} 
39c0: 7b 0a 09 09 09 63 6f 6e 74 69 6e 75 65 0a 09 09  {....continue...
39d0: 7d 0a 0a 09 09 6c 61 70 70 65 6e 64 20 70 75 62  }....lappend pub
39e0: 6c 69 63 4b 65 79 73 20 24 72 6f 77 28 70 75 62  licKeys $row(pub
39f0: 6c 69 63 4b 65 79 29 0a 0a 09 09 73 65 74 20 63  licKey)....set c
3a00: 68 61 6e 67 65 52 65 71 75 69 72 65 64 20 31 0a  hangeRequired 1.
3a10: 09 7d 0a 7d 0a 0a 70 72 6f 63 20 61 75 74 68 6f  .}.}..proc autho
3a20: 72 69 7a 65 55 73 65 72 20 7b 70 61 73 73 77 6f  rizeUser {passwo
3a30: 72 64 4e 61 6d 65 20 75 73 65 72 4e 61 6d 65 7d  rdName userName}
3a40: 20 7b 0a 09 72 65 74 75 72 6e 20 5b 61 75 74 68   {..return [auth
3a50: 6f 72 69 7a 65 55 73 65 72 73 20 24 70 61 73 73  orizeUsers $pass
3a60: 77 6f 72 64 4e 61 6d 65 20 24 75 73 65 72 4e 61  wordName $userNa
3a70: 6d 65 5d 0a 7d 0a 0a 70 72 6f 63 20 64 65 61 75  me].}..proc deau
3a80: 74 68 6f 72 69 7a 65 55 73 65 72 73 20 7b 70 61  thorizeUsers {pa
3a90: 73 73 77 6f 72 64 4e 61 6d 65 20 61 72 67 73 7d  sswordName args}
3aa0: 20 7b 0a 09 73 65 74 20 75 73 65 72 73 20 24 61   {..set users $a
3ab0: 72 67 73 0a 0a 09 5f 6d 6f 64 69 66 79 50 75 62  rgs..._modifyPub
3ac0: 6c 69 63 4b 65 79 73 20 24 70 61 73 73 77 6f 72  licKeys $passwor
3ad0: 64 4e 61 6d 65 20 24 75 73 65 72 73 20 7b 0a 09  dName $users {..
3ae0: 09 73 65 74 20 69 64 78 20 5b 6c 73 65 61 72 63  .set idx [lsearc
3af0: 68 20 2d 65 78 61 63 74 20 24 70 75 62 6c 69 63  h -exact $public
3b00: 4b 65 79 73 20 24 72 6f 77 28 70 75 62 6c 69 63  Keys $row(public
3b10: 4b 65 79 29 5d 0a 09 09 69 66 20 7b 24 69 64 78  Key)]...if {$idx
3b20: 20 3d 3d 20 2d 31 7d 20 7b 0a 09 09 09 63 6f 6e   == -1} {....con
3b30: 74 69 6e 75 65 0a 09 09 7d 0a 0a 09 09 73 65 74  tinue...}....set
3b40: 20 70 75 62 6c 69 63 4b 65 79 73 20 5b 6c 72 65   publicKeys [lre
3b50: 70 6c 61 63 65 20 24 70 75 62 6c 69 63 4b 65 79  place $publicKey
3b60: 73 20 24 69 64 78 20 24 69 64 78 5d 0a 0a 09 09  s $idx $idx]....
3b70: 73 65 74 20 63 68 61 6e 67 65 52 65 71 75 69 72  set changeRequir
3b80: 65 64 20 31 0a 09 7d 0a 7d 0a 0a 70 72 6f 63 20  ed 1..}.}..proc 
3b90: 64 65 61 75 74 68 6f 72 69 7a 65 55 73 65 72 20  deauthorizeUser 
3ba0: 7b 70 61 73 73 77 6f 72 64 4e 61 6d 65 20 75 73  {passwordName us
3bb0: 65 72 4e 61 6d 65 7d 20 7b 0a 09 72 65 74 75 72  erName} {..retur
3bc0: 6e 20 5b 64 65 61 75 74 68 6f 72 69 7a 65 55 73  n [deauthorizeUs
3bd0: 65 72 73 20 24 70 61 73 73 77 6f 72 64 4e 61 6d  ers $passwordNam
3be0: 65 20 24 75 73 65 72 4e 61 6d 65 5d 0a 7d 0a 0a  e $userName].}..
3bf0: 70 72 6f 63 20 77 68 6f 61 6d 69 20 7b 7d 20 7b  proc whoami {} {
3c00: 0a 09 66 6f 72 65 61 63 68 20 73 6c 6f 74 49 6e  ..foreach slotIn
3c10: 66 6f 44 69 63 74 20 5b 5f 6c 69 73 74 43 65 72  foDict [_listCer
3c20: 74 69 66 69 63 61 74 65 73 5d 20 7b 0a 09 09 75  tificates] {...u
3c30: 6e 73 65 74 20 2d 6e 6f 63 6f 6d 70 6c 61 69 6e  nset -nocomplain
3c40: 20 73 6c 6f 74 49 6e 66 6f 0a 09 09 61 72 72 61   slotInfo...arra
3c50: 79 20 73 65 74 20 73 6c 6f 74 49 6e 66 6f 20 24  y set slotInfo $
3c60: 73 6c 6f 74 49 6e 66 6f 44 69 63 74 0a 0a 09 09  slotInfoDict....
3c70: 73 65 74 20 70 75 62 6b 65 79 20 24 73 6c 6f 74  set pubkey $slot
3c80: 49 6e 66 6f 28 70 75 62 6b 65 79 29 0a 0a 09 09  Info(pubkey)....
3c90: 75 6e 73 65 74 20 2d 6e 6f 63 6f 6d 70 6c 61 69  unset -nocomplai
3ca0: 6e 20 72 6f 77 0a 09 09 64 62 20 65 76 61 6c 20  n row...db eval 
3cb0: 7b 53 45 4c 45 43 54 20 6e 61 6d 65 20 46 52 4f  {SELECT name FRO
3cc0: 4d 20 75 73 65 72 73 20 57 48 45 52 45 20 70 75  M users WHERE pu
3cd0: 62 6c 69 63 4b 65 79 20 3d 20 24 70 75 62 6b 65  blicKey = $pubke
3ce0: 79 3b 7d 20 72 6f 77 20 7b 0a 09 09 09 73 65 74  y;} row {....set
3cf0: 20 75 73 65 72 73 28 24 72 6f 77 28 6e 61 6d 65   users($row(name
3d00: 29 29 20 31 0a 09 09 7d 0a 09 7d 0a 0a 09 70 75  )) 1...}..}...pu
3d10: 74 73 20 5b 6a 6f 69 6e 20 5b 61 72 72 61 79 20  ts [join [array 
3d20: 6e 61 6d 65 73 20 75 73 65 72 73 5d 20 7b 2c 20  names users] {, 
3d30: 7d 5d 0a 7d 0a 0a 70 72 6f 63 20 68 65 6c 70 20  }].}..proc help 
3d40: 7b 7b 61 63 74 69 6f 6e 20 22 22 7d 7d 20 7b 0a  {{action ""}} {.
3d50: 09 5f 70 72 69 6e 74 48 65 6c 70 20 73 74 64 6f  ._printHelp stdo
3d60: 75 74 20 24 61 63 74 69 6f 6e 0a 7d 0a 23 20 45  ut $action.}.# E
3d70: 6e 64 20 75 73 65 72 20 43 4c 49 20 66 75 6e 63  nd user CLI func
3d80: 74 69 6f 6e 73 0a 0a 23 23 23 20 4d 41 49 4e 0a  tions..### MAIN.
3d90: 0a 73 71 6c 69 74 65 33 20 64 62 20 24 70 61 73  .sqlite3 db $pas
3da0: 73 77 6f 72 64 46 69 6c 65 0a 0a 64 62 20 65 76  swordFile..db ev
3db0: 61 6c 20 7b 0a 09 43 52 45 41 54 45 20 54 41 42  al {..CREATE TAB
3dc0: 4c 45 20 49 46 20 4e 4f 54 20 45 58 49 53 54 53  LE IF NOT EXISTS
3dd0: 20 75 73 65 72 73 28 6e 61 6d 65 2c 20 70 75 62   users(name, pub
3de0: 6c 69 63 4b 65 79 20 42 4c 4f 42 29 3b 0a 09 43  licKey BLOB);..C
3df0: 52 45 41 54 45 20 54 41 42 4c 45 20 49 46 20 4e  REATE TABLE IF N
3e00: 4f 54 20 45 58 49 53 54 53 20 70 61 73 73 77 6f  OT EXISTS passwo
3e10: 72 64 73 28 6e 61 6d 65 2c 20 65 6e 63 72 79 70  rds(name, encryp
3e20: 74 65 64 50 61 73 73 20 42 4c 4f 42 2c 20 65 6e  tedPass BLOB, en
3e30: 63 72 79 70 74 65 64 4b 65 79 20 42 4c 4f 42 2c  cryptedKey BLOB,
3e40: 20 70 75 62 6c 69 63 4b 65 79 20 42 4c 4f 42 2c   publicKey BLOB,
3e50: 20 76 65 72 69 66 69 63 61 74 69 6f 6e 20 42 4c   verification BL
3e60: 4f 42 29 3b 0a 7d 0a 0a 69 66 20 7b 24 61 63 74  OB);.}..if {$act
3e70: 69 6f 6e 20 69 6e 20 24 76 61 6c 69 64 43 6f 6d  ion in $validCom
3e80: 6d 61 6e 64 73 7d 20 7b 0a 09 69 66 20 7b 5b 63  mands} {..if {[c
3e90: 61 74 63 68 20 7b 0a 09 09 24 61 63 74 69 6f 6e  atch {...$action
3ea0: 20 7b 2a 7d 24 61 72 67 76 0a 09 7d 20 65 72 72   {*}$argv..} err
3eb0: 6f 72 5d 7d 20 7b 0a 09 09 70 75 74 73 20 73 74  or]} {...puts st
3ec0: 64 65 72 72 20 22 45 72 72 6f 72 3a 20 24 65 72  derr "Error: $er
3ed0: 72 6f 72 22 0a 0a 09 09 65 78 69 74 20 31 0a 09  ror"....exit 1..
3ee0: 7d 0a 7d 20 65 6c 73 65 20 7b 0a 09 70 75 74 73  }.} else {..puts
3ef0: 20 73 74 64 65 72 72 20 22 49 6e 76 61 6c 69 64   stderr "Invalid
3f00: 20 61 63 74 69 6f 6e 22 0a 0a 09 65 78 69 74 20   action"...exit 
3f10: 31 0a 7d 0a 0a 65 78 69 74 20 30 0a 0a           1.}..exit 0..