summaryrefslogtreecommitdiffstats
path: root/models/publickey.go
diff options
context:
space:
mode:
Diffstat (limited to 'models/publickey.go')
-rw-r--r--models/publickey.go81
1 files changed, 81 insertions, 0 deletions
diff --git a/models/publickey.go b/models/publickey.go
index fbba691abc..41233d0c39 100644
--- a/models/publickey.go
+++ b/models/publickey.go
@@ -6,6 +6,8 @@ package models
import (
"bufio"
+ "encoding/base64"
+ "encoding/binary"
"errors"
"fmt"
"io"
@@ -111,6 +113,85 @@ var (
}
)
+func extractTypeFromBase64Key(key string) (string, error) {
+ b, err := base64.StdEncoding.DecodeString(key)
+ if err != nil || len(b) < 4 {
+ return "", errors.New("Invalid key format")
+ }
+
+ keyLength := int(binary.BigEndian.Uint32(b))
+
+ if len(b) < 4+keyLength {
+ return "", errors.New("Invalid key format")
+ }
+
+ return string(b[4 : 4+keyLength]), nil
+}
+
+// Parse any key string in openssh or ssh2 format to clean openssh string (rfc4253)
+func ParseKeyString(content string) (string, error) {
+
+ // Transform all legal line endings to a single "\n"
+ s := strings.Replace(strings.Replace(strings.TrimSpace(content), "\r\n", "\n", -1), "\r", "\n", -1)
+
+ lines := strings.Split(s, "\n")
+
+ var keyType, keyContent, keyComment string
+
+ if len(lines) == 1 {
+ // Parse openssh format
+ parts := strings.Fields(lines[0])
+ switch len(parts) {
+ case 0:
+ return "", errors.New("Empty key")
+ case 1:
+ keyContent = parts[0]
+ case 2:
+ keyType = parts[0]
+ keyContent = parts[1]
+ default:
+ keyType = parts[0]
+ keyContent = parts[1]
+ keyComment = parts[2]
+ }
+
+ // If keyType is not given, extract it from content. If given, validate it
+ if len(keyType) == 0 {
+ if t, err := extractTypeFromBase64Key(keyContent); err == nil {
+ keyType = t
+ } else {
+ return "", err
+ }
+ } else {
+ if t, err := extractTypeFromBase64Key(keyContent); err != nil || keyType != t {
+ return "", err
+ }
+ }
+ } else {
+ // Parse SSH2 file format.
+ continuationLine := false
+
+ for _, line := range lines {
+ // Skip lines that:
+ // 1) are a continuation of the previous line,
+ // 2) contain ":" as that are comment lines
+ // 3) contain "-" as that are begin and end tags
+ if continuationLine || strings.ContainsAny(line, ":-") {
+ continuationLine = strings.HasSuffix(line, "\\")
+ } else {
+ keyContent = keyContent + line
+ }
+ }
+
+ if t, err := extractTypeFromBase64Key(keyContent); err == nil {
+ keyType = t
+ } else {
+ return "", err
+ }
+ }
+ return keyType + " " + keyContent + " " + keyComment, nil
+}
+
// CheckPublicKeyString checks if the given public key string is recognized by SSH.
func CheckPublicKeyString(content string) (bool, error) {
content = strings.TrimRight(content, "\n\r")