Commit 3dac3cb8 authored by Leigh Stoller's avatar Leigh Stoller

Changes to make it easier for ProtoGeni users!

* When generating an encrypted SSL certificate, derive an SSH public
  key from the private key and store in the pubkeys table for the
  user. Note that SSH version 2 RSA keys are actually just openssl RSA
  keys, and that ssh-keygen can extract an ssh compatible public key
  from it.

* Change getsslcert.php3 to return the ssh private and public key when
  give the "ssh" boolean argument. This is mostly for the benefit of
  Flack; we probably need a better UI for the user to get this stuff. 

* Remove the requirement that users must upload an SSH key to use
  protogeni, since we now create one for them when they create their
  encrypted SSL certificate.

* Some cleanup; instead of looking at the comment field to determine
  what pubkeys are Emulab created (and should not be deleted), use new
  internal and nodelete flags.
parent 2b5246b9
#!/usr/bin/perl -wT
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2011 University of Utah and the Flux Group.
# Copyright (c) 2000-2012 University of Utah and the Flux Group.
# All rights reserved.
#
use English;
......@@ -31,7 +31,7 @@ sub usage()
print " -r Force a regenerate of initial key for user\n";
exit(-1);
}
my $optlist = "dkniwfu:rX:s";
my $optlist = "dkniwfu:rX:sRNC:S:";
my $iskey = 0;
my $verify = 0;
my $initmode = 0;
......@@ -39,6 +39,9 @@ my $force = 0;
my $genmode = 0;
my $nobody = 0;
my $noemail = 0;
my $remove = 0;
my $nodelete = 0;
my $Comment;
my $xmlfile;
#
......@@ -147,9 +150,15 @@ if (defined($options{"n"})) {
if (defined($options{"i"})) {
$initmode = 1;
}
if (defined($options{"N"})) {
$nodelete = 1;
}
if (defined($options{"r"})) {
$force = 1;
}
if (defined($options{"R"})) {
$remove = 1;
}
if (defined($options{"s"})) {
$noemail = 1;
}
......@@ -159,6 +168,9 @@ if (defined($options{"w"})) {
if (defined($options{"u"})) {
$user = $options{"u"};
}
if (defined($options{"C"})) {
$Comment = $options{"C"};
}
if (defined($options{"X"})) {
$xmlfile = $options{"X"};
......@@ -383,13 +395,21 @@ sub ParseKey($) {
# Make up a comment field for the DB.
#
if (!defined($comment)) {
$comment = "$type-${user_email}";
$comment = (defined($Comment) ? $Comment : "$type-${user_email}");
}
$key = "$key $comment";
my $safe_key = DBQuoteSpecial($key);
my $safe_comment = DBQuoteSpecial($comment);
DBQueryFatal("replace into user_pubkeys ".
"values ('$user_uid', '$user_dbid', ".
" 0, '$key', now(), '$comment')");
if ($remove) {
DBQueryFatal("delete from user_pubkeys ".
"where uid_idx='$user_dbid' and comment=$safe_comment");
}
DBQueryFatal("replace into user_pubkeys set ".
" uid='$user_uid', uid_idx='$user_dbid', ".
" internal='0', nodelete='$nodelete', ".
" idx=NULL, stamp=now(), ".
" pubkey=$safe_key, comment=$safe_comment");
#
# Mark user record as modified so nodes are updated.
......@@ -469,9 +489,10 @@ sub InitUser()
my $ident = `cat $sshdir/identity.pub`;
if ($ident =~ /(\d*\s\d*\s[0-9a-zA-Z]*)\s([-\w\@\.]*)/) {
DBQueryFatal("replace into user_pubkeys ".
"values ('$user_uid', '$user_dbid', ".
" 0, '$1 $2', now(), '$2')");
DBQueryFatal("replace into user_pubkeys set ".
" uid='$user_uid', uid_idx='$user_dbid', ".
" internal='1', nodelete='1', idx=NULL, stamp=now(), ".
" pubkey='$1 $2', comment='$2'");
}
else {
fatal("Bad protocol 1 public key: $ident\n");
......@@ -512,9 +533,10 @@ sub InitUser()
if ($ident =~
/^(ssh-rsa [-\w\.\@\+\/\=]*) ([-\w\@\.\ ]*)$/) {
DBQueryFatal("replace into user_pubkeys ".
"values ('$user_uid', '$user_dbid', ".
" 0, '$1 $2', now(), '$2')");
DBQueryFatal("replace into user_pubkeys set ".
" uid='$user_uid', uid_idx='$user_dbid', ".
" internal='1', nodelete='1', idx=NULL, stamp=now(), ".
" pubkey='$1 $2', comment='$2'");
}
else {
fatal("Bad protocol 2 public key: $ident\n");
......
#!/usr/bin/perl -wT
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2011 University of Utah and the Flux Group.
# Copyright (c) 2000-2012 University of Utah and the Flux Group.
# All rights reserved.
#
use strict;
......@@ -53,6 +53,8 @@ my $CACONFIG = "$SSLDIR/ca.cnf";
my $EMULAB_CERT = "$TB/etc/emulab.pem";
my $EMULAB_KEY = "$TB/etc/emulab.key";
my $OPENSSL = "/usr/bin/openssl";
my $KEYGEN = "/usr/bin/ssh-keygen";
my $ADDKEY = "$TB/sbin/addpubkey";
my $WORKDIR = "$TB/ssl";
my $SAVEUID = $UID;
......@@ -471,6 +473,43 @@ if ($encrypted) {
chown($user_number, $default_groupgid, "$target")
or fatal("Could not chown $target: $!");
chmod(0600, $target)
or fatal("Could not chmod $target: $!");
#
# Create an SSH key from the private key. Mostly for geni users,
# who tend not to know how to do such things.
#
my $pemfile = "$ssldir/encrypted.pem";
my $sshdir = "$USERDIR/$user_uid/.ssh";
my $pphrase = User::escapeshellarg($password);
# This comment is special. It functions as a cross table reference
# between pubkeys and sslcerts. I might do this differently later.
my $comment = User::escapeshellarg("sslcert:${serial}");
# ssh-keygen whines and refuses to extract unless the mode is 600.
chmod(0600, $pemfile)
or fatal("Could not chmod $pemfile: $!");
system("$KEYGEN -P $pphrase -y -f $pemfile > $sshdir/encrypted.pub") == 0
or fatal("Could not extract ssh pubkey from $pemfile");
#
# The key format is identical to openssh, so just copy it over.
#
system("/bin/cp usercert_key.pem $sshdir/encrypted.key") == 0
or fatal("Could not copy private key to $sshdir/encrypted.key: $!");
chmod(0600, "$sshdir/encrypted.key")
or fatal("Could not chmod $sshdir/encrypted.key: $!");
#
# And add the pubkey to the DB. Mark it as nodelete and that it should
# remove existing key with same comment.
#
$EUID = $UID;
system("$ADDKEY -s -N -R -C $comment -u $user_uid -f $sshdir/encrypted.pub")
== 0 or fatal("Could not add pubkey $sshdir/encrypted.pub");
}
TBScriptUnlock();
......
#!/usr/bin/perl -w
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2011 University of Utah and the Flux Group.
# Copyright (c) 2000-2012 University of Utah and the Flux Group.
# All rights reserved.
#
use English;
......@@ -342,11 +342,6 @@ if (exists($xmlparse->{'attribute'}->{'passphrase'}) &&
fatal("Checkpass failed with $?");
}
$newuser_args{'initial_passphrase'} = $passphrase;
if (! (exists($xmlparse->{'attribute'}->{'pubkey'}) ||
exists($xmlparse->{'pubkeys'}))) {
UserError("Must provide SSH pubkey when requesting SSL Certificate")
}
}
#
......
......@@ -459,7 +459,7 @@ sub AddUser()
if (defined($target_user->initial_passphrase())) {
my $pphrase = User::escapeshellarg($target_user->initial_passphrase());
system("$MKUSERCERT -p '$pphrase' $user");
system("$MKUSERCERT -p $pphrase $user");
if ($?) {
fatal("Could not create initial encrypted SSL certificate");
}
......
......@@ -1135,8 +1135,8 @@ sub SSLCert($$$;$)
}
#
# Get user ssh keys. This is bogus; I am making sure not to return the
# emulab key which is not encrypted. The keys table needs work.
# Get user ssh keys, but do not include the "internal" keys, which
# are the Emulab generated unencrypted keys.
#
sub GetSSHKeys($$)
{
......@@ -1151,8 +1151,7 @@ sub GetSSHKeys($$)
my $query_result =
DBQueryWarn("select pubkey from user_pubkeys ".
"where uid_idx='$uid_idx' and ".
" comment not like '%${OURDOMAIN}'");
"where uid_idx='$uid_idx' and internal=0");
return -1
if (!defined($query_result));
......@@ -1179,8 +1178,7 @@ sub DeleteSSHKeys($)
my $query_result =
DBQueryWarn("delete from user_pubkeys ".
"where uid_idx='$uid_idx' and ".
" comment not like '%${OURDOMAIN}'");
"where uid_idx='$uid_idx' and internal=0");
return -1
if (!defined($query_result));
......@@ -1189,8 +1187,7 @@ sub DeleteSSHKeys($)
}
#
# Get (hopefully) unencrypted, locally-generated user ssh keys. This is
# bogus; I am making sure to only return locally-generated keys.
# Get (hopefully) unencrypted, locally-generated user ssh keys.
#
sub GetDefaultSSHKeys($$;$)
{
......@@ -1210,8 +1207,7 @@ sub GetDefaultSSHKeys($$;$)
my $query_result =
DBQueryWarn("select pubkey from user_pubkeys ".
"where uid_idx='$uid_idx' and ".
" comment like '%\@${OURDOMAIN}' $extra");
"where uid_idx='$uid_idx' and internal=1 $extra");
return -1
if (!defined($query_result));
......@@ -1761,11 +1757,17 @@ sub HomeDir($)
sub escapeshellarg($)
{
my ($str) = @_;
my ($str) = @_;
my @chars = split('', $str);
my $result = "";
$str =~ s/[^[:alnum:]]/\\$&/g;
$str =~ /^(.+)$/; # untaint the result
return $1;
foreach my $ch (@chars) {
if ($ch eq '\'') {
$result = $result . "\'\\\'";
}
$result = $result . "$ch";
}
return "'$result'";
}
#
......
<?php
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2011 University of Utah and the Flux Group.
# Copyright (c) 2000-2012 University of Utah and the Flux Group.
# All rights reserved.
#
# Database Constants
......@@ -33,6 +33,9 @@ $TBDB_MMLENGTH = 64;
$TBDB_ARCHIVE_TAGLEN = 64;
$TBDB_ARCHIVE_MSGLEN = 2048;
# Minimum length.
$TBDB_MINPASSPHRASE = 10;
#
# Current policy is to prefix the EID with the PID. Make sure it is not
# too long for the database. PID is 12, and the max is 32, so the user
......
<?php
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2003, 2006, 2007 University of Utah and the Flux Group.
# Copyright (c) 2000-2012 University of Utah and the Flux Group.
# All rights reserved.
#
include("defs.php3");
......@@ -47,9 +47,18 @@ if (! mysql_num_rows($query_result)) {
USERERROR("Public Key for user '$target_uid' does not exist!", 1);
}
$row = mysql_fetch_array($query_result);
$pubkey = $row['pubkey'];
$chunky = chunk_split($pubkey, 70, "<br>\n");
$row = mysql_fetch_array($query_result);
$pubkey = $row['pubkey'];
$chunky = chunk_split($pubkey, 70, "<br>\n");
$internal = $row['internal'];
$nodelete = $row['nodelete'];
#
# Internal keys cannot be deleted without admin.
#
if (($internal || $nodelete) && !$isadmin) {
USERERROR("You are not allowed to delete your system keys!", 1);
}
#
# We run this twice. The first time we are checking for a confirmation
......@@ -94,6 +103,11 @@ if (!isset($confirmed)) {
<td>$chunky</td>
</tr>
</table>\n";
if ($internal || $nodelete) {
echo "<center><font color=red size=+1>";
echo "This is an internal key!</font><center>";
}
PAGEFOOTER();
return;
......
<?php
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2009 University of Utah and the Flux Group.
# Copyright (c) 2000-2012 University of Utah and the Flux Group.
# All rights reserved.
#
include("defs.php3");
......@@ -17,10 +17,14 @@ $isadmin = ISADMIN();
# Verify page arguments
#
$optargs = OptionalPageArguments("target_user", PAGEARG_USER,
"p12", PAGEARG_BOOLEAN);
"p12", PAGEARG_BOOLEAN,
"ssh", PAGEARG_BOOLEAN);
if (!isset($p12)) {
$p12 = 0;
}
if (!isset($ssh)) {
$ssh = 0;
}
# Default to current user if not provided.
if (!isset($target_user)) {
......@@ -58,7 +62,7 @@ if ($p12) {
}
$query_result =& $target_user->TableLookUp("user_sslcerts",
"cert,privkey",
"cert,privkey,idx",
"encrypted=1 and revoked is null");
if (!mysql_num_rows($query_result)) {
......@@ -69,12 +73,34 @@ $row = mysql_fetch_array($query_result);
$cert = $row["cert"];
$key = $row["privkey"];
header("Content-Type: text/plain");
echo "-----BEGIN RSA PRIVATE KEY-----\n";
echo $key;
echo "-----END RSA PRIVATE KEY-----\n";
echo "-----BEGIN CERTIFICATE-----\n";
echo $cert;
echo "-----END CERTIFICATE-----\n";
if ($ssh) {
$serial = $row['idx'];
$comment = "sslcert:${serial}";
$pubkey_result =& $target_user->TableLookUp("user_pubkeys",
"pubkey",
"comment='$comment'");
if (!mysql_num_rows($query_result)) {
PAGEHEADER("Download SSL Certificate for $target_uid");
USERERROR("There is no SSH pubkey for certificate!", 1);
}
$row = mysql_fetch_array($pubkey_result);
$pubkey = $row['pubkey'];
header("Content-Type: text/plain");
echo "-----BEGIN RSA PRIVATE KEY-----\n";
echo $key;
echo "-----END RSA PRIVATE KEY-----\n";
echo $pubkey;
echo "\n";
}
else {
header("Content-Type: text/plain");
echo "-----BEGIN RSA PRIVATE KEY-----\n";
echo $key;
echo "-----END RSA PRIVATE KEY-----\n";
echo "-----BEGIN CERTIFICATE-----\n";
echo $cert;
echo "-----END CERTIFICATE-----\n";
}
?>
<?php
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2011 University of Utah and the Flux Group.
# Copyright (c) 2000-2012 University of Utah and the Flux Group.
# All rights reserved.
#
include("defs.php3");
......@@ -738,6 +738,10 @@ if (! $returning) {
elseif ($formfields["passphrase1"] != $formfields["passphrase2"]) {
$errors["Confirm Pass Phrase"] = "Does not match Pass Phrase";
}
elseif (strlen($formfields["passphrase1"]) < $TBDB_MINPASSPHRASE) {
$errors["Pass Phrase"] =
"Too short; $TBDB_MINPASSPHRASE char minimum";
}
elseif (! CHECKPASSWORD(($USERSELECTUIDS ?
$formfields["joining_uid"] : "ignored"),
$formfields["passphrase1"],
......@@ -745,12 +749,6 @@ if (! $returning) {
$formfields["usr_email"], $checkerror)) {
$errors["Pass Phrase"] = "$checkerror";
}
if (! (isset($_FILES['usr_keyfile']) &&
$_FILES['usr_keyfile']['name'] != "" &&
$_FILES['usr_keyfile']['name'] != "none")) {
$errors["SSH Pub Key"] =
"You must provide an SSH pubkey to use Geni";
}
}
}
if (!$forwikionly) {
......
<?php
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2011 University of Utah and the Flux Group.
# Copyright (c) 2000-2012 University of Utah and the Flux Group.
# All rights reserved.
#
include("defs.php3");
......@@ -869,6 +869,10 @@ if (! $returning) {
elseif ($formfields["passphrase1"] != $formfields["passphrase2"]) {
$errors["Confirm Pass Phrase"] = "Does not match Pass Phrase";
}
elseif (strlen($formfields["passphrase1"]) < $TBDB_MINPASSPHRASE) {
$errors["Pass Phrase"] =
"Too short; $TBDB_MINPASSPHRASE char minimum";
}
elseif (! CHECKPASSWORD(($USERSELECTUIDS ?
$formfields["proj_head_uid"] : "ignored"),
$formfields["passphrase1"],
......@@ -876,12 +880,6 @@ if (! $returning) {
$formfields["usr_email"], $checkerror)) {
$errors["Pass Phrase"] = "$checkerror";
}
if (! (isset($_FILES['usr_keyfile']) &&
$_FILES['usr_keyfile']['name'] != "" &&
$_FILES['usr_keyfile']['name'] != "none")) {
$errors["SSH Pub Key"] =
"You must provide an SSH pubkey to use Geni";
}
}
}
......
<?php
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2007 University of Utah and the Flux Group.
# Copyright (c) 2000-2012 University of Utah and the Flux Group.
# All rights reserved.
#
include("defs.php3");
......@@ -75,21 +75,28 @@ function SPITFORM($formfields, $errors)
$pubkey = $row['pubkey'];
$date = $row['stamp'];
$idx = $row['idx'];
$internal= $row['internal'];
$nodelete= $row['nodelete'];
$fnote = "";
if (strstr($comment, $BOSSNODE)) {
if ($internal || $nodelete) {
$fnote = "[<b>1</b>]";
}
$chunky = chunk_split("$pubkey $fnote", 75, "<br>\n");
$delurl = CreateURL("deletepubkey", $target_user, "key", $idx);
echo "<tr>
<td align=center>
<A href='$delurl'>
<img alt='Delete Key' src=redball.gif></A>
</td>
<td>$chunky</td>
echo "<tr>\n";
if (($internal || $nodelete) && !$isadmin) {
echo "<td>&nbsp</td>";
}
else {
echo "<td align=center>
<A href='$delurl'>
<img alt='Delete Key' src=redball.gif></A>
</td>";
}
echo " <td>$chunky</td>
</tr>\n";
}
echo "</table>\n";
......@@ -101,7 +108,7 @@ function SPITFORM($formfields, $errors)
}
echo "<blockquote><blockquote><blockquote>
<ol>
<li> Please do not delete your Emulab generated public key.
<li> Your Emulab generated public keys may not be deleted.
</ol>
</blockquote></blockquote></blockquote>\n";
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment