parseKeyString parses any key string in OpenSSH or SSH2 format to clean OpenSSH string (RFC4253).
(content string)
| 105 | |
| 106 | // parseKeyString parses any key string in OpenSSH or SSH2 format to clean OpenSSH string (RFC4253). |
| 107 | func parseKeyString(content string) (string, error) { |
| 108 | // Transform all legal line endings to a single "\n" |
| 109 | |
| 110 | // Replace all windows full new lines ("\r\n") |
| 111 | content = strings.ReplaceAll(content, "\r\n", "\n") |
| 112 | |
| 113 | // Replace all windows half new lines ("\r"), if it happen not to match replace above |
| 114 | content = strings.ReplaceAll(content, "\r", "\n") |
| 115 | |
| 116 | // Replace ending new line as its may cause unwanted behaviour (extra line means not a single line key | OpenSSH key) |
| 117 | content = strings.TrimRight(content, "\n") |
| 118 | |
| 119 | // split lines |
| 120 | lines := strings.Split(content, "\n") |
| 121 | |
| 122 | var keyType, keyContent, keyComment string |
| 123 | |
| 124 | if len(lines) == 1 { |
| 125 | // Parse OpenSSH format. |
| 126 | parts := strings.SplitN(lines[0], " ", 3) |
| 127 | switch len(parts) { |
| 128 | case 0: |
| 129 | return "", errors.New("empty key") |
| 130 | case 1: |
| 131 | keyContent = parts[0] |
| 132 | case 2: |
| 133 | keyType = parts[0] |
| 134 | keyContent = parts[1] |
| 135 | default: |
| 136 | keyType = parts[0] |
| 137 | keyContent = parts[1] |
| 138 | keyComment = parts[2] |
| 139 | } |
| 140 | |
| 141 | // If keyType is not given, extract it from content. If given, validate it. |
| 142 | t, err := extractTypeFromBase64Key(keyContent) |
| 143 | if err != nil { |
| 144 | return "", errors.Newf("extractTypeFromBase64Key: %v", err) |
| 145 | } |
| 146 | if keyType == "" { |
| 147 | keyType = t |
| 148 | } else if keyType != t { |
| 149 | return "", errors.Newf("key type and content does not match: %s - %s", keyType, t) |
| 150 | } |
| 151 | } else { |
| 152 | // Parse SSH2 file format. |
| 153 | continuationLine := false |
| 154 | |
| 155 | for _, line := range lines { |
| 156 | // Skip lines that: |
| 157 | // 1) are a continuation of the previous line, |
| 158 | // 2) contain ":" as that are comment lines |
| 159 | // 3) contain "-" as that are begin and end tags |
| 160 | if continuationLine || strings.ContainsAny(line, ":-") { |
| 161 | continuationLine = strings.HasSuffix(line, "\\") |
| 162 | } else { |
| 163 | keyContent = keyContent + line |
| 164 | } |
no test coverage detected